OSDN Git Service

388dea61d88ab6fed763b8c8e2e29dcf70220cad
[android-x86/system-extras.git] / perfprofd / binder_interface / perfprofd_binder.cc
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 <chrono>
21 #include <condition_variable>
22 #include <cstdlib>
23 #include <fstream>
24 #include <memory>
25 #include <mutex>
26 #include <string>
27 #include <thread>
28 #include <functional>
29
30 #include <inttypes.h>
31 #include <unistd.h>
32
33 #include <android-base/logging.h>
34 #include <android-base/stringprintf.h>
35 #include <android/os/DropBoxManager.h>
36 #include <binder/BinderService.h>
37 #include <binder/IResultReceiver.h>
38 #include <binder/Status.h>
39 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
40 #include <utils/String16.h>
41 #include <utils/String8.h>
42 #include <utils/Vector.h>
43
44 #include "android/os/BnPerfProfd.h"
45 #include "perfprofd_config.pb.h"
46 #include "perf_profile.pb.h"
47
48 #include "config.h"
49 #include "perfprofdcore.h"
50
51 namespace android {
52 namespace perfprofd {
53 namespace binder {
54
55 using Status = ::android::binder::Status;
56
57 class BinderConfig : public Config {
58  public:
59   bool send_to_dropbox = true;
60
61   bool is_profiling = false;
62
63   void Sleep(size_t seconds) override {
64     if (seconds == 0) {
65       return;
66     }
67     std::unique_lock<std::mutex> guard(mutex_);
68     using namespace std::chrono_literals;
69     cv_.wait_for(guard, seconds * 1s, [&]() { return interrupted_; });
70   }
71   bool ShouldStopProfiling() override {
72     std::unique_lock<std::mutex> guard(mutex_);
73     return interrupted_;
74   }
75
76   void ResetStopProfiling() {
77     std::unique_lock<std::mutex> guard(mutex_);
78     interrupted_ = false;
79   }
80   void StopProfiling() {
81     std::unique_lock<std::mutex> guard(mutex_);
82     interrupted_ = true;
83     cv_.notify_all();
84   }
85
86   bool IsProfilingEnabled() const override {
87     return true;
88   }
89
90   // Operator= to simplify setting the config values. This will retain the
91   // original mutex, condition-variable etc.
92   BinderConfig& operator=(const BinderConfig& rhs) {
93     // Copy base fields.
94     *static_cast<Config*>(this) = static_cast<const Config&>(rhs);
95
96     send_to_dropbox = rhs.send_to_dropbox;
97
98     return *this;
99   }
100
101  private:
102   std::mutex mutex_;
103   std::condition_variable cv_;
104   bool interrupted_ = false;
105 };
106
107 class PerfProfdNativeService : public BinderService<PerfProfdNativeService>,
108                                public ::android::os::BnPerfProfd {
109  public:
110   static status_t start();
111   static int Main();
112
113   static char const* getServiceName() { return "perfprofd"; }
114
115   status_t dump(int fd, const Vector<String16> &args) override;
116
117   Status startProfiling(int32_t profilingDuration,
118                                 int32_t profilingInterval,
119                                 int32_t iterations) override;
120   Status startProfilingProtobuf(const std::vector<uint8_t>& config_proto) override;
121
122   Status stopProfiling() override;
123
124   // Override onTransact so we can handle shellCommand.
125   status_t onTransact(uint32_t _aidl_code,
126                       const Parcel& _aidl_data,
127                       Parcel* _aidl_reply,
128                       uint32_t _aidl_flags = 0) override;
129
130  private:
131   // Handler for ProfilingLoop.
132   bool BinderHandler(wireless_android_play_playlog::AndroidPerfProfile* encodedProfile,
133                      Config* config);
134   // Helper for the handler.
135   HandlerFn GetBinderHandler();
136
137   status_t shellCommand(int /*in*/, int out, int err, Vector<String16>& args);
138
139   template <typename ConfigFn> Status StartProfiling(ConfigFn fn);
140   template <typename ProtoLoaderFn> Status StartProfilingProtobuf(ProtoLoaderFn fn);
141   Status StartProfilingProtobufFd(int fd);
142
143   std::mutex lock_;
144
145   BinderConfig cur_config_;
146
147   int seq_ = 0;
148 };
149
150 bool PerfProfdNativeService::BinderHandler(
151     wireless_android_play_playlog::AndroidPerfProfile* encodedProfile,
152     Config* config) {
153   CHECK(config != nullptr);
154   if (static_cast<BinderConfig*>(config)->send_to_dropbox) {
155     size_t size = encodedProfile->ByteSize();
156     std::unique_ptr<uint8_t[]> data(new uint8_t[size]);
157     encodedProfile->SerializeWithCachedSizesToArray(data.get());
158
159     using DropBoxManager = android::os::DropBoxManager;
160     sp<DropBoxManager> dropbox(new DropBoxManager());
161     Status status = dropbox->addData(String16("perfprofd"),
162                                      data.get(),
163                                      size,
164                                      0);
165     if (!status.isOk()) {
166       LOG(WARNING) << "Failed dropbox submission: " << status.exceptionCode()
167                    << " " << status.exceptionMessage().c_str();
168     }
169     return status.isOk();
170   }
171
172   if (encodedProfile == nullptr) {
173     return false;
174   }
175   std::string data_file_path(config->destination_directory);
176   data_file_path += "/perf.data";
177   std::string path = android::base::StringPrintf("%s.encoded.%d", data_file_path.c_str(), seq_);
178   PROFILE_RESULT result = SerializeProtobuf(encodedProfile, path.c_str());
179   if (result != PROFILE_RESULT::OK_PROFILE_COLLECTION) {
180     return false;
181   }
182
183   seq_++;
184   return true;
185 }
186
187 HandlerFn PerfProfdNativeService::GetBinderHandler() {
188   return HandlerFn(std::bind(&PerfProfdNativeService::BinderHandler,
189                              this,
190                              std::placeholders::_1,
191                              std::placeholders::_2));
192 }
193
194 status_t PerfProfdNativeService::start() {
195   IPCThreadState::self()->disableBackgroundScheduling(true);
196   status_t ret = BinderService<PerfProfdNativeService>::publish();
197   if (ret != android::OK) {
198     return ret;
199   }
200   sp<ProcessState> ps(ProcessState::self());
201   ps->startThreadPool();
202   ps->giveThreadPoolName();
203   return android::OK;
204 }
205
206 status_t PerfProfdNativeService::dump(int fd, const Vector<String16> &args) {
207   auto out = std::fstream(base::StringPrintf("/proc/self/fd/%d", fd));
208   out << "Nothing to log, yet!" << std::endl;
209
210   return NO_ERROR;
211 }
212
213 Status PerfProfdNativeService::startProfiling(int32_t profilingDuration,
214                                               int32_t profilingInterval,
215                                               int32_t iterations) {
216   auto config_fn = [&](BinderConfig& config) {
217     config = BinderConfig();  // Reset to a default config.
218
219     config.sample_duration_in_s = static_cast<uint32_t>(profilingDuration);
220     config.collection_interval_in_s = static_cast<uint32_t>(profilingInterval);
221     config.main_loop_iterations = static_cast<uint32_t>(iterations);
222   };
223   return StartProfiling(config_fn);
224 }
225 Status PerfProfdNativeService::startProfilingProtobuf(const std::vector<uint8_t>& config_proto) {
226   auto proto_loader_fn = [&config_proto](ProfilingConfig& proto_config) {
227     return proto_config.ParseFromArray(config_proto.data(), config_proto.size());
228   };
229   return StartProfilingProtobuf(proto_loader_fn);
230 }
231
232 template <typename ConfigFn>
233 Status PerfProfdNativeService::StartProfiling(ConfigFn fn) {
234   std::lock_guard<std::mutex> guard(lock_);
235
236   if (cur_config_.is_profiling) {
237     // TODO: Define error code?
238     return binder::Status::fromServiceSpecificError(1);
239   }
240   cur_config_.is_profiling = true;
241   cur_config_.ResetStopProfiling();
242
243   fn(cur_config_);
244
245   HandlerFn handler = GetBinderHandler();
246   auto profile_runner = [handler](PerfProfdNativeService* service) {
247     ProfilingLoop(service->cur_config_, handler);
248
249     // This thread is done.
250     std::lock_guard<std::mutex> unset_guard(service->lock_);
251     service->cur_config_.is_profiling = false;
252   };
253   std::thread profiling_thread(profile_runner, this);
254   profiling_thread.detach();  // Let it go.
255
256   return binder::Status::ok();
257 }
258
259 template <typename ProtoLoaderFn>
260 Status PerfProfdNativeService::StartProfilingProtobuf(ProtoLoaderFn fn) {
261   ProfilingConfig proto_config;
262   if (!fn(proto_config)) {
263     return binder::Status::fromExceptionCode(2);
264   }
265   auto config_fn = [&proto_config](BinderConfig& config) {
266     config = BinderConfig();  // Reset to a default config.
267
268     // Copy proto values.
269 #define CHECK_AND_COPY_FROM_PROTO(name)      \
270     if (proto_config.has_ ## name ()) {      \
271       config. name = proto_config. name ();  \
272     }
273     CHECK_AND_COPY_FROM_PROTO(collection_interval_in_s)
274     CHECK_AND_COPY_FROM_PROTO(use_fixed_seed)
275     CHECK_AND_COPY_FROM_PROTO(main_loop_iterations)
276     CHECK_AND_COPY_FROM_PROTO(destination_directory)
277     CHECK_AND_COPY_FROM_PROTO(config_directory)
278     CHECK_AND_COPY_FROM_PROTO(perf_path)
279     CHECK_AND_COPY_FROM_PROTO(sampling_period)
280     CHECK_AND_COPY_FROM_PROTO(sample_duration_in_s)
281     CHECK_AND_COPY_FROM_PROTO(only_debug_build)
282     CHECK_AND_COPY_FROM_PROTO(hardwire_cpus)
283     CHECK_AND_COPY_FROM_PROTO(hardwire_cpus_max_duration_in_s)
284     CHECK_AND_COPY_FROM_PROTO(max_unprocessed_profiles)
285     CHECK_AND_COPY_FROM_PROTO(stack_profile)
286     CHECK_AND_COPY_FROM_PROTO(collect_cpu_utilization)
287     CHECK_AND_COPY_FROM_PROTO(collect_charging_state)
288     CHECK_AND_COPY_FROM_PROTO(collect_booting)
289     CHECK_AND_COPY_FROM_PROTO(collect_camera_active)
290     CHECK_AND_COPY_FROM_PROTO(process)
291     CHECK_AND_COPY_FROM_PROTO(use_elf_symbolizer)
292     CHECK_AND_COPY_FROM_PROTO(send_to_dropbox)
293 #undef CHECK_AND_COPY_FROM_PROTO
294   };
295   return StartProfiling(config_fn);
296 }
297
298 Status PerfProfdNativeService::StartProfilingProtobufFd(int fd) {
299   auto proto_loader_fn = [fd](ProfilingConfig& proto_config) {
300     struct IstreamCopyingInputStream : public google::protobuf::io::CopyingInputStream {
301       IstreamCopyingInputStream(int fd_in)
302                 : stream(base::StringPrintf("/proc/self/fd/%d", fd_in),
303                          std::ios::binary | std::ios::in) {
304       }
305
306       int Read(void* buffer, int size) override {
307         stream.read(reinterpret_cast<char*>(buffer), size);
308         size_t count = stream.gcount();
309         if (count > 0) {
310           return count;
311         }
312         return -1;
313       }
314
315       std::ifstream stream;
316     };
317     std::unique_ptr<IstreamCopyingInputStream> is(new IstreamCopyingInputStream(fd));
318     std::unique_ptr<google::protobuf::io::CopyingInputStreamAdaptor> is_adaptor(
319         new google::protobuf::io::CopyingInputStreamAdaptor(is.get()));
320     return proto_config.ParseFromZeroCopyStream(is_adaptor.get());
321   };
322   return StartProfilingProtobuf(proto_loader_fn);
323 }
324
325 Status PerfProfdNativeService::stopProfiling() {
326   std::lock_guard<std::mutex> guard(lock_);
327   if (!cur_config_.is_profiling) {
328     // TODO: Define error code?
329     return Status::fromServiceSpecificError(1);
330   }
331
332   cur_config_.StopProfiling();
333
334   return Status::ok();
335 }
336
337 status_t PerfProfdNativeService::shellCommand(int in,
338                                               int out,
339                                               int err,
340                                               Vector<String16>& args) {
341   if (android::base::kEnableDChecks) {
342     LOG(VERBOSE) << "Perfprofd::shellCommand";
343
344     for (size_t i = 0, n = args.size(); i < n; i++) {
345       LOG(VERBOSE) << "  arg[" << i << "]: '" << String8(args[i]).string() << "'";
346     }
347   }
348
349   if (args.size() >= 1) {
350     if (args[0] == String16("dump")) {
351       dump(out, args);
352       return OK;
353     } else if (args[0] == String16("startProfiling")) {
354       if (args.size() < 4) {
355         return BAD_VALUE;
356       }
357       // TODO: handle invalid strings.
358       int32_t duration = strtol(String8(args[1]).string(), nullptr, 0);
359       int32_t interval = strtol(String8(args[2]).string(), nullptr, 0);
360       int32_t iterations = strtol(String8(args[3]).string(), nullptr, 0);
361       Status status = startProfiling(duration, interval, iterations);
362       if (status.isOk()) {
363         return OK;
364       } else {
365         return status.serviceSpecificErrorCode();
366       }
367     } else if (args[0] == String16("startProfilingProto")) {
368       if (args.size() < 2) {
369         return BAD_VALUE;
370       }
371       int fd = -1;
372       if (args[1] == String16("-")) {
373         fd = in;
374       } else {
375         // TODO: Implement reading from disk?
376       }
377       if (fd < 0) {
378         return BAD_VALUE;
379       }
380       binder::Status status = StartProfilingProtobufFd(fd);
381       if (status.isOk()) {
382         return OK;
383       } else {
384         return status.serviceSpecificErrorCode();
385       }
386     } else if (args[0] == String16("stopProfiling")) {
387       Status status = stopProfiling();
388       if (status.isOk()) {
389         return OK;
390       } else {
391         return status.serviceSpecificErrorCode();
392       }
393     }
394   }
395   return BAD_VALUE;
396 }
397
398 status_t PerfProfdNativeService::onTransact(uint32_t _aidl_code,
399                                             const Parcel& _aidl_data,
400                                             Parcel* _aidl_reply,
401                                             uint32_t _aidl_flags) {
402   switch (_aidl_code) {
403     case IBinder::SHELL_COMMAND_TRANSACTION: {
404       int in = _aidl_data.readFileDescriptor();
405       int out = _aidl_data.readFileDescriptor();
406       int err = _aidl_data.readFileDescriptor();
407       int argc = _aidl_data.readInt32();
408       Vector<String16> args;
409       for (int i = 0; i < argc && _aidl_data.dataAvail() > 0; i++) {
410         args.add(_aidl_data.readString16());
411       }
412       sp<IBinder> unusedCallback;
413       sp<IResultReceiver> resultReceiver;
414       status_t status;
415       if ((status = _aidl_data.readNullableStrongBinder(&unusedCallback)) != OK)
416         return status;
417       if ((status = _aidl_data.readNullableStrongBinder(&resultReceiver)) != OK)
418         return status;
419       status = shellCommand(in, out, err, args);
420       if (resultReceiver != nullptr) {
421         resultReceiver->send(status);
422       }
423       return OK;
424     }
425
426     default:
427       return BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
428   }
429 }
430
431 int Main() {
432   android::status_t ret;
433   if ((ret = PerfProfdNativeService::start()) != android::OK) {
434     LOG(ERROR) << "Unable to start InstalldNativeService: %d" << ret;
435     exit(1);
436   }
437
438   android::IPCThreadState::self()->joinThreadPool();
439
440   LOG(INFO) << "Exiting perfprofd";
441   return 0;
442 }
443
444 }  // namespace binder
445 }  // namespace perfprofd
446 }  // namespace android