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