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 out << "Nothing to log, yet!" << std::endl;
112
113 return NO_ERROR;
114 }
115
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)116 Status 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) {
125 auto config_fn = [&](ThreadedConfig& config) {
126 config = ThreadedConfig(); // Reset to a default config.
127
128 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;
149 };
150 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();
155 }
startProfilingString(const String16 & config)156 Status 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) {
162 if (!reader.Read(arg, /* fail_on_error */ true)) {
163 error_msg = base::StringPrintf("Could not parse %s", arg.c_str());
164 return Status::fromExceptionCode(1, error_msg.c_str());
165 }
166 }
167 auto config_fn = [&](ThreadedConfig& config) {
168 config = ThreadedConfig(); // Reset to a default config.
169 reader.FillConfig(&config);
170 };
171 if (!StartProfiling(config_fn, &error_msg)) {
172 return Status::fromExceptionCode(1, error_msg.c_str());
173 }
174 return Status::ok();
175 }
startProfilingProtobuf(const std::vector<uint8_t> & config_proto)176 Status PerfProfdNativeService::startProfilingProtobuf(const std::vector<uint8_t>& config_proto) {
177 auto proto_loader_fn = [&config_proto](ProfilingConfig& proto_config) {
178 return proto_config.ParseFromArray(config_proto.data(), config_proto.size());
179 };
180 return StartProfilingProtobuf(proto_loader_fn);
181 }
182
183 template <typename ProtoLoaderFn>
StartProfilingProtobuf(ProtoLoaderFn fn)184 Status PerfProfdNativeService::StartProfilingProtobuf(ProtoLoaderFn fn) {
185 ProfilingConfig proto_config;
186 if (!fn(proto_config)) {
187 return binder::Status::fromExceptionCode(2);
188 }
189 auto config_fn = [&proto_config](ThreadedConfig& config) {
190 config = ThreadedConfig(); // Reset to a default config.
191
192 // Copy proto values.
193 #define CHECK_AND_COPY_FROM_PROTO(name) \
194 if (proto_config.has_ ## name ()) { \
195 config. name = proto_config. name (); \
196 }
197 CHECK_AND_COPY_FROM_PROTO(collection_interval_in_s)
198 CHECK_AND_COPY_FROM_PROTO(use_fixed_seed)
199 CHECK_AND_COPY_FROM_PROTO(main_loop_iterations)
200 CHECK_AND_COPY_FROM_PROTO(destination_directory)
201 CHECK_AND_COPY_FROM_PROTO(config_directory)
202 CHECK_AND_COPY_FROM_PROTO(perf_path)
203 CHECK_AND_COPY_FROM_PROTO(sampling_period)
204 CHECK_AND_COPY_FROM_PROTO(sample_duration_in_s)
205 CHECK_AND_COPY_FROM_PROTO(only_debug_build)
206 CHECK_AND_COPY_FROM_PROTO(hardwire_cpus)
207 CHECK_AND_COPY_FROM_PROTO(hardwire_cpus_max_duration_in_s)
208 CHECK_AND_COPY_FROM_PROTO(max_unprocessed_profiles)
209 CHECK_AND_COPY_FROM_PROTO(stack_profile)
210 CHECK_AND_COPY_FROM_PROTO(collect_cpu_utilization)
211 CHECK_AND_COPY_FROM_PROTO(collect_charging_state)
212 CHECK_AND_COPY_FROM_PROTO(collect_booting)
213 CHECK_AND_COPY_FROM_PROTO(collect_camera_active)
214 CHECK_AND_COPY_FROM_PROTO(process)
215 CHECK_AND_COPY_FROM_PROTO(use_elf_symbolizer)
216 CHECK_AND_COPY_FROM_PROTO(send_to_dropbox)
217 CHECK_AND_COPY_FROM_PROTO(compress)
218 #undef CHECK_AND_COPY_FROM_PROTO
219 };
220 std::string error_msg;
221 if (!StartProfiling(config_fn, &error_msg)) {
222 return Status::fromExceptionCode(1, error_msg.c_str());
223 }
224 return Status::ok();
225 }
226
StartProfilingProtobufFd(int fd)227 Status PerfProfdNativeService::StartProfilingProtobufFd(int fd) {
228 auto proto_loader_fn = [fd](ProfilingConfig& proto_config) {
229 struct IstreamCopyingInputStream : public google::protobuf::io::CopyingInputStream {
230 IstreamCopyingInputStream(int fd_in)
231 : stream(base::StringPrintf("/proc/self/fd/%d", fd_in),
232 std::ios::binary | std::ios::in) {
233 }
234
235 int Read(void* buffer, int size) override {
236 stream.read(reinterpret_cast<char*>(buffer), size);
237 size_t count = stream.gcount();
238 if (count > 0) {
239 return count;
240 }
241 return -1;
242 }
243
244 std::ifstream stream;
245 };
246 std::unique_ptr<IstreamCopyingInputStream> is(new IstreamCopyingInputStream(fd));
247 std::unique_ptr<google::protobuf::io::CopyingInputStreamAdaptor> is_adaptor(
248 new google::protobuf::io::CopyingInputStreamAdaptor(is.get()));
249 return proto_config.ParseFromZeroCopyStream(is_adaptor.get());
250 };
251 return StartProfilingProtobuf(proto_loader_fn);
252 }
253
stopProfiling()254 Status PerfProfdNativeService::stopProfiling() {
255 std::string error_msg;
256 if (!StopProfiling(&error_msg)) {
257 Status::fromExceptionCode(1, error_msg.c_str());
258 }
259 return Status::ok();
260 }
261
shellCommand(int in,int out,int err_fd,Vector<String16> & args)262 status_t PerfProfdNativeService::shellCommand(int in,
263 int out,
264 int err_fd,
265 Vector<String16>& args) {
266 if (android::base::kEnableDChecks) {
267 LOG(VERBOSE) << "Perfprofd::shellCommand";
268
269 for (size_t i = 0, n = args.size(); i < n; i++) {
270 LOG(VERBOSE) << " arg[" << i << "]: '" << String8(args[i]).string() << "'";
271 }
272 }
273
274 auto err_str = std::fstream(base::StringPrintf("/proc/self/fd/%d", err_fd));
275
276 if (args.size() >= 1) {
277 if (args[0] == String16("dump")) {
278 dump(out, args);
279 return OK;
280 } else if (args[0] == String16("startProfiling")) {
281 ConfigReader reader;
282 for (size_t i = 1; i < args.size(); ++i) {
283 if (!reader.Read(String8(args[i]).string(), /* fail_on_error */ true)) {
284 err_str << base::StringPrintf("Could not parse %s", String8(args[i]).string())
285 << std::endl;
286 return BAD_VALUE;
287 }
288 }
289 auto config_fn = [&](ThreadedConfig& config) {
290 config = ThreadedConfig(); // Reset to a default config.
291 reader.FillConfig(&config);
292 };
293 std::string error_msg;
294 if (!StartProfiling(config_fn, &error_msg)) {
295 err_str << error_msg << std::endl;
296 return UNKNOWN_ERROR;
297 }
298 return OK;
299 } else if (args[0] == String16("startProfilingProto")) {
300 if (args.size() < 2) {
301 return BAD_VALUE;
302 }
303 int fd = -1;
304 if (args[1] == String16("-")) {
305 fd = in;
306 } else {
307 // TODO: Implement reading from disk?
308 }
309 if (fd < 0) {
310 err_str << "Bad file descriptor " << args[1] << std::endl;
311 return BAD_VALUE;
312 }
313 binder::Status status = StartProfilingProtobufFd(fd);
314 if (status.isOk()) {
315 return OK;
316 } else {
317 err_str << status.toString8() << std::endl;
318 return UNKNOWN_ERROR;
319 }
320 } else if (args[0] == String16("stopProfiling")) {
321 Status status = stopProfiling();
322 if (status.isOk()) {
323 return OK;
324 } else {
325 err_str << status.toString8() << std::endl;
326 return UNKNOWN_ERROR;
327 }
328 }
329 }
330 return BAD_VALUE;
331 }
332
onTransact(uint32_t _aidl_code,const Parcel & _aidl_data,Parcel * _aidl_reply,uint32_t _aidl_flags)333 status_t PerfProfdNativeService::onTransact(uint32_t _aidl_code,
334 const Parcel& _aidl_data,
335 Parcel* _aidl_reply,
336 uint32_t _aidl_flags) {
337 switch (_aidl_code) {
338 case IBinder::SHELL_COMMAND_TRANSACTION: {
339 int in = _aidl_data.readFileDescriptor();
340 int out = _aidl_data.readFileDescriptor();
341 int err = _aidl_data.readFileDescriptor();
342 int argc = _aidl_data.readInt32();
343 Vector<String16> args;
344 for (int i = 0; i < argc && _aidl_data.dataAvail() > 0; i++) {
345 args.add(_aidl_data.readString16());
346 }
347 sp<IBinder> unusedCallback;
348 sp<IResultReceiver> resultReceiver;
349 status_t status;
350 if ((status = _aidl_data.readNullableStrongBinder(&unusedCallback)) != OK)
351 return status;
352 if ((status = _aidl_data.readNullableStrongBinder(&resultReceiver)) != OK)
353 return status;
354 status = shellCommand(in, out, err, args);
355 if (resultReceiver != nullptr) {
356 resultReceiver->send(status);
357 }
358 return OK;
359 }
360
361 default:
362 return ::android::os::BnPerfProfd::onTransact(
363 _aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
364 }
365 }
366
367 } // namespace
368
Main()369 int Main() {
370 android::status_t ret;
371 if ((ret = PerfProfdNativeService::start()) != android::OK) {
372 LOG(ERROR) << "Unable to start InstalldNativeService: %d" << ret;
373 exit(1);
374 }
375
376 android::IPCThreadState::self()->joinThreadPool();
377
378 LOG(INFO) << "Exiting perfprofd";
379 return 0;
380 }
381
382 } // namespace binder
383 } // namespace perfprofd
384 } // namespace android
385