• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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