1 /** 2 * Copyright (c) 2016, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "dumpstate" 18 19 #include "DumpstateService.h" 20 21 #include <memory> 22 23 #include <android-base/stringprintf.h> 24 #include "android/os/BnDumpstate.h" 25 26 #include "DumpstateInternal.h" 27 28 using android::base::StringPrintf; 29 30 namespace android { 31 namespace os { 32 33 namespace { 34 35 struct DumpstateInfo { 36 public: 37 Dumpstate* ds = nullptr; 38 int32_t calling_uid = -1; 39 std::string calling_package; 40 }; 41 42 static binder::Status exception(uint32_t code, const std::string& msg) { 43 MYLOGE("%s (%d) ", msg.c_str(), code); 44 return binder::Status::fromExceptionCode(code, String8(msg.c_str())); 45 } 46 47 // Creates a bugreport and exits, thus preserving the oneshot nature of the service. 48 // Note: takes ownership of data. 49 [[noreturn]] static void* dumpstate_thread_main(void* data) { 50 std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data)); 51 ds_info->ds->Run(ds_info->calling_uid, ds_info->calling_package); 52 MYLOGD("Finished taking a bugreport. Exiting.\n"); 53 exit(0); 54 } 55 56 [[noreturn]] static void signalErrorAndExit(sp<IDumpstateListener> listener, int error_code) { 57 listener->onError(error_code); 58 exit(0); 59 } 60 61 class DumpstateToken : public BnDumpstateToken {}; 62 63 } // namespace 64 65 DumpstateService::DumpstateService() : ds_(nullptr) { 66 } 67 68 char const* DumpstateService::getServiceName() { 69 return "dumpstate"; 70 } 71 72 status_t DumpstateService::Start() { 73 IPCThreadState::self()->disableBackgroundScheduling(true); 74 status_t ret = BinderService<DumpstateService>::publish(); 75 if (ret != android::OK) { 76 return ret; 77 } 78 sp<ProcessState> ps(ProcessState::self()); 79 ps->startThreadPool(); 80 ps->giveThreadPoolName(); 81 return android::OK; 82 } 83 84 // Note: this method is part of the old flow and is not expected to be used in combination 85 // with startBugreport. 86 binder::Status DumpstateService::setListener(const std::string& name, 87 const sp<IDumpstateListener>& listener, 88 bool getSectionDetails, 89 sp<IDumpstateToken>* returned_token) { 90 *returned_token = nullptr; 91 if (name.empty()) { 92 MYLOGE("setListener(): name not set\n"); 93 return binder::Status::ok(); 94 } 95 if (listener == nullptr) { 96 MYLOGE("setListener(): listener not set\n"); 97 return binder::Status::ok(); 98 } 99 std::lock_guard<std::mutex> lock(lock_); 100 if (ds_ == nullptr) { 101 ds_ = &(Dumpstate::GetInstance()); 102 } 103 if (ds_->listener_ != nullptr) { 104 MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_->listener_name_.c_str()); 105 return binder::Status::ok(); 106 } 107 108 ds_->listener_name_ = name; 109 ds_->listener_ = listener; 110 ds_->report_section_ = getSectionDetails; 111 *returned_token = new DumpstateToken(); 112 113 return binder::Status::ok(); 114 } 115 116 binder::Status DumpstateService::startBugreport(int32_t calling_uid, 117 const std::string& calling_package, 118 const android::base::unique_fd& bugreport_fd, 119 const android::base::unique_fd& screenshot_fd, 120 int bugreport_mode, 121 const sp<IDumpstateListener>& listener) { 122 MYLOGI("startBugreport() with mode: %d\n", bugreport_mode); 123 124 // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a 125 // time. 126 std::lock_guard<std::mutex> lock(lock_); 127 if (ds_ != nullptr) { 128 MYLOGE("Error! There is already a bugreport in progress. Returning."); 129 if (listener != nullptr) { 130 listener->onError(IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS); 131 } 132 return exception(binder::Status::EX_SERVICE_SPECIFIC, 133 "There is already a bugreport in progress"); 134 } 135 136 // From here on, all conditions that indicate we are done with this incoming request should 137 // result in exiting the service to free it up for next invocation. 138 if (listener == nullptr) { 139 MYLOGE("Invalid input: no listener"); 140 exit(0); 141 } 142 143 if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL && 144 bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE && 145 bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_REMOTE && 146 bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WEAR && 147 bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_TELEPHONY && 148 bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WIFI && 149 bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_DEFAULT) { 150 MYLOGE("Invalid input: bad bugreport mode: %d", bugreport_mode); 151 signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); 152 } 153 154 if (bugreport_fd.get() == -1 || screenshot_fd.get() == -1) { 155 // TODO(b/111441001): screenshot fd should be optional 156 MYLOGE("Invalid filedescriptor"); 157 signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); 158 } 159 160 std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>(); 161 options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd, 162 screenshot_fd); 163 164 ds_ = &(Dumpstate::GetInstance()); 165 ds_->SetOptions(std::move(options)); 166 ds_->listener_ = listener; 167 168 DumpstateInfo* ds_info = new DumpstateInfo(); 169 ds_info->ds = ds_; 170 ds_info->calling_uid = calling_uid; 171 ds_info->calling_package = calling_package; 172 173 pthread_t thread; 174 status_t err = pthread_create(&thread, nullptr, dumpstate_thread_main, ds_info); 175 if (err != 0) { 176 delete ds_info; 177 ds_info = nullptr; 178 MYLOGE("Could not create a thread"); 179 signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR); 180 } 181 return binder::Status::ok(); 182 } 183 184 binder::Status DumpstateService::cancelBugreport() { 185 // This is a no-op since the cancellation is done from java side via setting sys properties. 186 // See BugreportManagerServiceImpl. 187 // TODO(b/111441001): maybe make native and java sides use different binder interface 188 // to avoid these annoyances. 189 return binder::Status::ok(); 190 } 191 192 status_t DumpstateService::dump(int fd, const Vector<String16>&) { 193 if (ds_ == nullptr) { 194 dprintf(fd, "Bugreport not in progress yet"); 195 return NO_ERROR; 196 } 197 std::string destination = ds_->options_->bugreport_fd.get() != -1 198 ? StringPrintf("[fd:%d]", ds_->options_->bugreport_fd.get()) 199 : ds_->bugreport_internal_dir_.c_str(); 200 dprintf(fd, "id: %d\n", ds_->id_); 201 dprintf(fd, "pid: %d\n", ds_->pid_); 202 dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false"); 203 dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_); 204 dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_); 205 dprintf(fd, "progress:\n"); 206 ds_->progress_->Dump(fd, " "); 207 dprintf(fd, "args: %s\n", ds_->options_->args.c_str()); 208 dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str()); 209 dprintf(fd, "version: %s\n", ds_->version_.c_str()); 210 dprintf(fd, "bugreport_dir: %s\n", destination.c_str()); 211 dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str()); 212 dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str()); 213 dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str()); 214 dprintf(fd, "path: %s\n", ds_->path_.c_str()); 215 dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str()); 216 dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str()); 217 dprintf(fd, "name: %s\n", ds_->name_.c_str()); 218 dprintf(fd, "now: %ld\n", ds_->now_); 219 dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false"); 220 dprintf(fd, "listener: %s\n", ds_->listener_name_.c_str()); 221 dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str()); 222 dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str()); 223 224 return NO_ERROR; 225 } 226 } // namespace os 227 } // namespace android 228