OSDN Git Service

Perfprofd: Implement startProfiling
[android-x86/system-extras.git] / perfprofd / perfprofd_binder.h
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 #ifndef SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_BINDER_H_
19 #define SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_BINDER_H_
20
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 <binder/BinderService.h>
34 #include <binder/IResultReceiver.h>
35 #include <binder/Status.h>
36 #include <utils/String16.h>
37 #include <utils/String8.h>
38 #include <utils/Vector.h>
39
40 #include "android/os/BnPerfProfd.h"
41
42 #include "config.h"
43 #include "configreader.h"
44 #include "perfprofdcore.h"
45
46 namespace android {
47 namespace perfprofd {
48
49 class PerfProfdNativeService : public BinderService<PerfProfdNativeService>,
50                                public os::BnPerfProfd {
51  private:
52   struct BinderConfig : public Config {
53     bool is_profiling = false;
54
55     void Sleep(size_t seconds) override {
56       // TODO: Replace with condition_variable::wait ...
57       sleep(seconds);
58     }
59   };
60
61  public:
62   static status_t start() {
63     IPCThreadState::self()->disableBackgroundScheduling(true);
64     status_t ret = BinderService<PerfProfdNativeService>::publish();
65     if (ret != android::OK) {
66       return ret;
67     }
68     sp<ProcessState> ps(ProcessState::self());
69     ps->startThreadPool();
70     ps->giveThreadPoolName();
71     return android::OK;
72   }
73
74   static char const* getServiceName() { return "perfprofd"; }
75
76   status_t dump(int fd, const Vector<String16> &args) override {
77     auto out = std::fstream(base::StringPrintf("/proc/self/fd/%d", fd));
78     out << "Nothing to log, yet!" << std::endl;
79
80     return NO_ERROR;
81   }
82
83   binder::Status startProfiling(int32_t profilingDuration,
84                                 int32_t profilingInterval,
85                                 int32_t iterations) override {
86     std::lock_guard<std::mutex> guard(lock_);
87
88     if (cur_config_.is_profiling) {
89       // TODO: Define error code?
90       return binder::Status::fromServiceSpecificError(1);
91     }
92     cur_config_.is_profiling = true;
93
94     ConfigReader().FillConfig(&cur_config_);  // Create a default config.
95
96     cur_config_.sample_duration_in_s = static_cast<uint32_t>(profilingDuration);
97     cur_config_.collection_interval_in_s = static_cast<uint32_t>(profilingInterval);
98     cur_config_.main_loop_iterations = static_cast<uint32_t>(iterations);
99
100     auto profile_runner = [](PerfProfdNativeService* service) {
101       ProfilingLoop(service->cur_config_);
102
103       // This thread is done.
104       std::lock_guard<std::mutex> unset_guard(service->lock_);
105       service->cur_config_.is_profiling = false;
106     };
107     std::thread profiling_thread(profile_runner, this);
108     profiling_thread.detach();  // Let it go.
109
110     return binder::Status::ok();
111   }
112
113   binder::Status stopProfiling() override {
114     UNIMPLEMENTED(ERROR) << "stopProfiling: To be implemented";
115     return binder::Status::fromExceptionCode(1);
116   }
117
118   // Override onTransact so we can handle shellCommand.
119   status_t onTransact(uint32_t _aidl_code,
120                       const Parcel& _aidl_data,
121                       Parcel* _aidl_reply,
122                       uint32_t _aidl_flags = 0) override {
123     switch (_aidl_code) {
124       case IBinder::SHELL_COMMAND_TRANSACTION: {
125         int in = _aidl_data.readFileDescriptor();
126         int out = _aidl_data.readFileDescriptor();
127         int err = _aidl_data.readFileDescriptor();
128         int argc = _aidl_data.readInt32();
129         Vector<String16> args;
130         for (int i = 0; i < argc && _aidl_data.dataAvail() > 0; i++) {
131           args.add(_aidl_data.readString16());
132         }
133         sp<IBinder> unusedCallback;
134         sp<IResultReceiver> resultReceiver;
135         status_t status;
136         if ((status = _aidl_data.readNullableStrongBinder(&unusedCallback)) != OK)
137           return status;
138         if ((status = _aidl_data.readNullableStrongBinder(&resultReceiver)) != OK)
139           return status;
140         status = shellCommand(in, out, err, args);
141         if (resultReceiver != nullptr) {
142           resultReceiver->send(status);
143         }
144         return OK;
145       }
146
147       default:
148         return BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
149     }
150   }
151
152  private:
153   status_t shellCommand(int /*in*/, int out, int err, Vector<String16>& args) {
154     if (android::base::kEnableDChecks) {
155       LOG(VERBOSE) << "Perfprofd::shellCommand";
156
157       for (size_t i = 0, n = args.size(); i < n; i++) {
158         LOG(VERBOSE) << "  arg[" << i << "]: '" << String8(args[i]).string() << "'";
159       }
160     }
161
162     if (args.size() >= 1) {
163       if (args[0] == String16("dump")) {
164         dump(out, args);
165         return OK;
166       } else if (args[0] == String16("startProfiling")) {
167         if (args.size() < 4) {
168           return BAD_VALUE;
169         }
170         // TODO: handle invalid strings.
171         int32_t duration = strtol(String8(args[1]).string(), nullptr, 0);
172         int32_t interval = strtol(String8(args[2]).string(), nullptr, 0);
173         int32_t iterations = strtol(String8(args[3]).string(), nullptr, 0);
174         binder::Status status = startProfiling(duration, interval, iterations);
175         if (status.isOk()) {
176           return OK;
177         } else {
178           return status.serviceSpecificErrorCode();
179         }
180       } else if (args[0] == String16("stopProfiling")) {
181         binder::Status status = stopProfiling();
182         if (status.isOk()) {
183           return OK;
184         } else {
185           return status.serviceSpecificErrorCode();
186         }
187       }
188     }
189     return BAD_VALUE;
190   }
191
192   std::mutex lock_;
193
194   BinderConfig cur_config_;
195 };
196
197 }  // namespace perfprofd
198 }  // namespace android
199
200 #endif  // SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_BINDER_H_