3 ** Copyright 2017, The Android Open Source Project
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
9 ** http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "perfprofd_binder.h"
21 #include <condition_variable>
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>
44 #include "android/os/BnPerfProfd.h"
45 #include "perfprofd_config.pb.h"
46 #include "perf_profile.pb.h"
49 #include "perfprofdcore.h"
55 using Status = ::android::binder::Status;
57 class BinderConfig : public Config {
59 bool send_to_dropbox = true;
61 bool is_profiling = false;
63 void Sleep(size_t seconds) override {
67 std::unique_lock<std::mutex> guard(mutex_);
68 using namespace std::chrono_literals;
69 cv_.wait_for(guard, seconds * 1s, [&]() { return interrupted_; });
71 bool ShouldStopProfiling() override {
72 std::unique_lock<std::mutex> guard(mutex_);
76 void ResetStopProfiling() {
77 std::unique_lock<std::mutex> guard(mutex_);
80 void StopProfiling() {
81 std::unique_lock<std::mutex> guard(mutex_);
86 bool IsProfilingEnabled() const override {
90 // Operator= to simplify setting the config values. This will retain the
91 // original mutex, condition-variable etc.
92 BinderConfig& operator=(const BinderConfig& rhs) {
94 *static_cast<Config*>(this) = static_cast<const Config&>(rhs);
96 send_to_dropbox = rhs.send_to_dropbox;
103 std::condition_variable cv_;
104 bool interrupted_ = false;
107 class PerfProfdNativeService : public BinderService<PerfProfdNativeService>,
108 public ::android::os::BnPerfProfd {
110 static status_t start();
113 static char const* getServiceName() { return "perfprofd"; }
115 status_t dump(int fd, const Vector<String16> &args) override;
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;
122 Status stopProfiling() override;
124 // Override onTransact so we can handle shellCommand.
125 status_t onTransact(uint32_t _aidl_code,
126 const Parcel& _aidl_data,
128 uint32_t _aidl_flags = 0) override;
131 // Handler for ProfilingLoop.
132 bool BinderHandler(wireless_android_play_playlog::AndroidPerfProfile* encodedProfile,
134 // Helper for the handler.
135 HandlerFn GetBinderHandler();
137 status_t shellCommand(int /*in*/, int out, int err, Vector<String16>& args);
139 template <typename ConfigFn> Status StartProfiling(ConfigFn fn);
140 template <typename ProtoLoaderFn> Status StartProfilingProtobuf(ProtoLoaderFn fn);
141 Status StartProfilingProtobufFd(int fd);
145 BinderConfig cur_config_;
150 bool PerfProfdNativeService::BinderHandler(
151 wireless_android_play_playlog::AndroidPerfProfile* encodedProfile,
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());
159 using DropBoxManager = android::os::DropBoxManager;
160 sp<DropBoxManager> dropbox(new DropBoxManager());
161 Status status = dropbox->addData(String16("perfprofd"),
165 if (!status.isOk()) {
166 LOG(WARNING) << "Failed dropbox submission: " << status.exceptionCode()
167 << " " << status.exceptionMessage().c_str();
169 return status.isOk();
172 if (encodedProfile == nullptr) {
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) {
187 HandlerFn PerfProfdNativeService::GetBinderHandler() {
188 return HandlerFn(std::bind(&PerfProfdNativeService::BinderHandler,
190 std::placeholders::_1,
191 std::placeholders::_2));
194 status_t PerfProfdNativeService::start() {
195 IPCThreadState::self()->disableBackgroundScheduling(true);
196 status_t ret = BinderService<PerfProfdNativeService>::publish();
197 if (ret != android::OK) {
200 sp<ProcessState> ps(ProcessState::self());
201 ps->startThreadPool();
202 ps->giveThreadPoolName();
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;
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.
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);
223 return StartProfiling(config_fn);
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());
229 return StartProfilingProtobuf(proto_loader_fn);
232 template <typename ConfigFn>
233 Status PerfProfdNativeService::StartProfiling(ConfigFn fn) {
234 std::lock_guard<std::mutex> guard(lock_);
236 if (cur_config_.is_profiling) {
237 // TODO: Define error code?
238 return binder::Status::fromServiceSpecificError(1);
240 cur_config_.is_profiling = true;
241 cur_config_.ResetStopProfiling();
245 HandlerFn handler = GetBinderHandler();
246 auto profile_runner = [handler](PerfProfdNativeService* service) {
247 ProfilingLoop(service->cur_config_, handler);
249 // This thread is done.
250 std::lock_guard<std::mutex> unset_guard(service->lock_);
251 service->cur_config_.is_profiling = false;
253 std::thread profiling_thread(profile_runner, this);
254 profiling_thread.detach(); // Let it go.
256 return binder::Status::ok();
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);
265 auto config_fn = [&proto_config](BinderConfig& config) {
266 config = BinderConfig(); // Reset to a default config.
268 // Copy proto values.
269 #define CHECK_AND_COPY_FROM_PROTO(name) \
270 if (proto_config.has_ ## name ()) { \
271 config. name = proto_config. name (); \
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
295 return StartProfiling(config_fn);
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) {
306 int Read(void* buffer, int size) override {
307 stream.read(reinterpret_cast<char*>(buffer), size);
308 size_t count = stream.gcount();
315 std::ifstream stream;
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());
322 return StartProfilingProtobuf(proto_loader_fn);
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);
332 cur_config_.StopProfiling();
337 status_t PerfProfdNativeService::shellCommand(int in,
340 Vector<String16>& args) {
341 if (android::base::kEnableDChecks) {
342 LOG(VERBOSE) << "Perfprofd::shellCommand";
344 for (size_t i = 0, n = args.size(); i < n; i++) {
345 LOG(VERBOSE) << " arg[" << i << "]: '" << String8(args[i]).string() << "'";
349 if (args.size() >= 1) {
350 if (args[0] == String16("dump")) {
353 } else if (args[0] == String16("startProfiling")) {
354 if (args.size() < 4) {
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);
365 return status.serviceSpecificErrorCode();
367 } else if (args[0] == String16("startProfilingProto")) {
368 if (args.size() < 2) {
372 if (args[1] == String16("-")) {
375 // TODO: Implement reading from disk?
380 binder::Status status = StartProfilingProtobufFd(fd);
384 return status.serviceSpecificErrorCode();
386 } else if (args[0] == String16("stopProfiling")) {
387 Status status = stopProfiling();
391 return status.serviceSpecificErrorCode();
398 status_t PerfProfdNativeService::onTransact(uint32_t _aidl_code,
399 const Parcel& _aidl_data,
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());
412 sp<IBinder> unusedCallback;
413 sp<IResultReceiver> resultReceiver;
415 if ((status = _aidl_data.readNullableStrongBinder(&unusedCallback)) != OK)
417 if ((status = _aidl_data.readNullableStrongBinder(&resultReceiver)) != OK)
419 status = shellCommand(in, out, err, args);
420 if (resultReceiver != nullptr) {
421 resultReceiver->send(status);
427 return BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
432 android::status_t ret;
433 if ((ret = PerfProfdNativeService::start()) != android::OK) {
434 LOG(ERROR) << "Unable to start InstalldNativeService: %d" << ret;
438 android::IPCThreadState::self()->joinThreadPool();
440 LOG(INFO) << "Exiting perfprofd";
444 } // namespace binder
445 } // namespace perfprofd
446 } // namespace android