• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
exception(uint32_t code,const std::string & msg,const std::string & extra_msg="")42 static binder::Status exception(uint32_t code, const std::string& msg,
43                                 const std::string& extra_msg = "") {
44     if (extra_msg.empty()) {
45         MYLOGE("%s (%d) ", msg.c_str(), code);
46     } else {
47         MYLOGE("%s %s (%d) ", msg.c_str(), extra_msg.c_str(), code);
48     }
49     return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
50 }
51 
52 // Creates a bugreport and exits, thus preserving the oneshot nature of the service.
53 // Note: takes ownership of data.
dumpstate_thread_bugreport(void * data)54 [[noreturn]] static void* dumpstate_thread_bugreport(void* data) {
55     std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data));
56     ds_info->ds->Run(ds_info->calling_uid, ds_info->calling_package);
57     MYLOGD("Finished taking a bugreport. Exiting.\n");
58     exit(0);
59 }
60 
dumpstate_thread_retrieve(void * data)61 [[noreturn]] static void* dumpstate_thread_retrieve(void* data) {
62     std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data));
63     ds_info->ds->Retrieve(ds_info->calling_uid, ds_info->calling_package);
64     MYLOGD("Finished retrieving a bugreport. Exiting.\n");
65     exit(0);
66 }
67 
signalErrorAndExit(sp<IDumpstateListener> listener,int error_code)68 [[noreturn]] static void signalErrorAndExit(sp<IDumpstateListener> listener, int error_code) {
69     listener->onError(error_code);
70     exit(0);
71 }
72 
73 }  // namespace
74 
DumpstateService()75 DumpstateService::DumpstateService() : ds_(nullptr), calling_uid_(-1), calling_package_() {
76 }
77 
getServiceName()78 char const* DumpstateService::getServiceName() {
79     return "dumpstate";
80 }
81 
Start()82 status_t DumpstateService::Start() {
83     IPCThreadState::self()->disableBackgroundScheduling(true);
84     status_t ret = BinderService<DumpstateService>::publish();
85     if (ret != android::OK) {
86         return ret;
87     }
88     sp<ProcessState> ps(ProcessState::self());
89     ps->startThreadPool();
90     ps->giveThreadPoolName();
91     return android::OK;
92 }
93 
preDumpUiData(const std::string &)94 binder::Status DumpstateService::preDumpUiData(const std::string&) {
95     std::lock_guard<std::mutex> lock(lock_);
96     MYLOGI("preDumpUiData()");
97 
98     if (ds_ != nullptr) {
99         MYLOGE("Error! DumpstateService is currently already being used. Returning.");
100         return exception(binder::Status::EX_SERVICE_SPECIFIC,
101                          "DumpstateService is already being used");
102     }
103 
104     ds_ = &(Dumpstate::GetInstance());
105     ds_->PreDumpUiData();
106 
107     return binder::Status::ok();
108 }
109 
startBugreport(int32_t calling_uid,const std::string & calling_package,android::base::unique_fd bugreport_fd,android::base::unique_fd screenshot_fd,int bugreport_mode,int bugreport_flags,const sp<IDumpstateListener> & listener,bool is_screenshot_requested)110 binder::Status DumpstateService::startBugreport(int32_t calling_uid,
111                                                 const std::string& calling_package,
112                                                 android::base::unique_fd bugreport_fd,
113                                                 android::base::unique_fd screenshot_fd,
114                                                 int bugreport_mode,
115                                                 int bugreport_flags,
116                                                 const sp<IDumpstateListener>& listener,
117                                                 bool is_screenshot_requested) {
118     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
119 
120     // Ensure there is only one bugreport in progress at a time.
121     std::lock_guard<std::mutex> lock(lock_);
122     if (ds_ != nullptr) {
123         MYLOGE("Error! DumpstateService is currently already being used. Returning.");
124         if (listener != nullptr) {
125             listener->onError(IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
126         }
127         return exception(binder::Status::EX_SERVICE_SPECIFIC,
128                          "DumpstateService is already being used");
129     }
130 
131     // From here on, all conditions that indicate we are done with this incoming request should
132     // result in exiting the service to free it up for next invocation.
133     if (listener == nullptr) {
134         MYLOGE("Invalid input: no listener");
135         exit(0);
136     }
137 
138     if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
139         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE &&
140         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_REMOTE &&
141         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WEAR &&
142         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_TELEPHONY &&
143         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WIFI &&
144         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_DEFAULT) {
145         MYLOGE("Invalid input: bad bugreport mode: %d", bugreport_mode);
146         signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
147     }
148 
149     std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
150     options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_flags,
151                         bugreport_fd, screenshot_fd, is_screenshot_requested);
152 
153     if (bugreport_fd.get() == -1 || (options->do_screenshot && screenshot_fd.get() == -1)) {
154         MYLOGE("Invalid filedescriptor");
155         signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
156     }
157 
158 
159     ds_ = &(Dumpstate::GetInstance());
160     ds_->SetOptions(std::move(options));
161     ds_->listener_ = listener;
162 
163     // Track caller info for cancellation purposes.
164     calling_uid_ = calling_uid;
165     calling_package_ = calling_package;
166 
167     DumpstateInfo* ds_info = new DumpstateInfo();
168     ds_info->ds = ds_;
169     ds_info->calling_uid = calling_uid;
170     ds_info->calling_package = calling_package;
171 
172     pthread_t thread;
173     // Initialize dumpstate
174     ds_->Initialize();
175     status_t err = pthread_create(&thread, nullptr, dumpstate_thread_bugreport, ds_info);
176     if (err != 0) {
177         delete ds_info;
178         MYLOGE("Could not create a thread");
179         signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
180     }
181     return binder::Status::ok();
182 }
183 
cancelBugreport(int32_t calling_uid,const std::string & calling_package)184 binder::Status DumpstateService::cancelBugreport(int32_t calling_uid,
185                                                  const std::string& calling_package) {
186     std::lock_guard<std::mutex> lock(lock_);
187     if (calling_uid != calling_uid_ || calling_package != calling_package_) {
188         // Note: we use a SecurityException to prevent BugreportManagerServiceImpl from killing the
189         // report in progress (from another caller).
190         return exception(
191             binder::Status::EX_SECURITY,
192             StringPrintf("Cancellation requested by %d/%s does not match report in "
193                          "progress",
194                          calling_uid, calling_package.c_str()),
195             // Sharing the owner of the BR is a (minor) leak, so leave it out of the app's exception
196             StringPrintf("started by %d/%s", calling_uid_, calling_package_.c_str()));
197     }
198     ds_->Cancel();
199     return binder::Status::ok();
200 }
201 
retrieveBugreport(int32_t calling_uid,const std::string & calling_package,android::base::unique_fd bugreport_fd,const std::string & bugreport_file,const sp<IDumpstateListener> & listener)202 binder::Status DumpstateService::retrieveBugreport(
203     int32_t calling_uid, const std::string& calling_package,
204     android::base::unique_fd bugreport_fd,
205     const std::string& bugreport_file,
206     const sp<IDumpstateListener>& listener) {
207 
208     ds_ = &(Dumpstate::GetInstance());
209     DumpstateInfo* ds_info = new DumpstateInfo();
210     ds_info->ds = ds_;
211     ds_info->calling_uid = calling_uid;
212     ds_info->calling_package = calling_package;
213     ds_->listener_ = listener;
214     std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
215     // Use a /dev/null FD when initializing options since none is provided.
216     android::base::unique_fd devnull_fd(
217         TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
218 
219     options->Initialize(Dumpstate::BugreportMode::BUGREPORT_DEFAULT,
220                         0, bugreport_fd, devnull_fd, false);
221 
222     if (bugreport_fd.get() == -1) {
223         MYLOGE("Invalid filedescriptor");
224         signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
225     }
226     ds_->SetOptions(std::move(options));
227     ds_->path_ = bugreport_file;
228     pthread_t thread;
229     status_t err = pthread_create(&thread, nullptr, dumpstate_thread_retrieve, ds_info);
230     if (err != 0) {
231         MYLOGE("Could not create a thread");
232         signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
233     }
234     return binder::Status::ok();
235 }
236 
dump(int fd,const Vector<String16> &)237 status_t DumpstateService::dump(int fd, const Vector<String16>&) {
238     std::lock_guard<std::mutex> lock(lock_);
239     if (ds_ == nullptr) {
240         dprintf(fd, "Bugreport not in progress yet");
241         return NO_ERROR;
242     }
243     std::string destination = ds_->options_->bugreport_fd.get() != -1
244                                   ? StringPrintf("[fd:%d]", ds_->options_->bugreport_fd.get())
245                                   : ds_->bugreport_internal_dir_.c_str();
246     dprintf(fd, "id: %d\n", ds_->id_);
247     dprintf(fd, "pid: %d\n", ds_->pid_);
248     dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false");
249     dprintf(fd, "last_percent_progress: %d\n", ds_->last_reported_percent_progress_);
250     dprintf(fd, "progress:\n");
251     ds_->progress_->Dump(fd, "  ");
252     dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
253     dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode_string.c_str());
254     dprintf(fd, "version: %s\n", ds_->version_.c_str());
255     dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
256     dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
257     dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str());
258     dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str());
259     dprintf(fd, "path: %s\n", ds_->path_.c_str());
260     dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
261     dprintf(fd, "name: %s\n", ds_->name_.c_str());
262     dprintf(fd, "now: %ld\n", ds_->now_);
263     dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
264     dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
265 
266     return NO_ERROR;
267 }
268 }  // namespace os
269 }  // namespace android
270