• Home
  • History
  • Annotate
  • 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 
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 
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 
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 
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 }
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 }
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>
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 
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 
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 
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 
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 
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