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 #define DEBUG false 17 #include "Log.h" 18 19 #include "IncidentService.h" 20 21 #include "FdBuffer.h" 22 #include "PrivacyFilter.h" 23 #include "Reporter.h" 24 #include "incidentd_util.h" 25 #include "section_list.h" 26 27 #include <android/os/IncidentReportArgs.h> 28 #include <binder/IPCThreadState.h> 29 #include <binder/IResultReceiver.h> 30 #include <binder/IServiceManager.h> 31 #include <binder/IShellCallback.h> 32 #include <log/log.h> 33 #include <private/android_filesystem_config.h> 34 #include <utils/Looper.h> 35 #include <thread> 36 37 #include <unistd.h> 38 39 enum { 40 WHAT_TAKE_REPORT = 1, 41 WHAT_SEND_BROADCASTS = 2 42 }; 43 44 #define DEFAULT_DELAY_NS (1000000000LL) 45 46 #define DEFAULT_BYTES_SIZE_LIMIT (400 * 1024 * 1024) // 400MB 47 #define DEFAULT_REFACTORY_PERIOD_MS (24 * 60 * 60 * 1000) // 1 Day 48 49 // Skip these sections (for dumpstate only) 50 // Skip logs (1100 - 1108), traces (1200 - 1202), dumpsys (3000 - 3024, 3027 - 3056, 4000 - 4001) 51 // because they are already in the bug report. 52 #define SKIPPED_DUMPSTATE_SECTIONS { \ 53 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, /* Logs */ \ 54 1200, 1201, 1202, /* Native, hal, java traces */ \ 55 3018, /* dumpsys meminfo*/ } 56 57 namespace android { 58 namespace os { 59 namespace incidentd { 60 61 String16 const APPROVE_INCIDENT_REPORTS("android.permission.APPROVE_INCIDENT_REPORTS"); 62 String16 const DUMP_PERMISSION("android.permission.DUMP"); 63 String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS"); 64 checkIncidentPermissions(const IncidentReportArgs & args)65 static Status checkIncidentPermissions(const IncidentReportArgs& args) { 66 uid_t callingUid = IPCThreadState::self()->getCallingUid(); 67 pid_t callingPid = IPCThreadState::self()->getCallingPid(); 68 if (callingUid == AID_ROOT || callingUid == AID_SHELL) { 69 // Root and shell are ok. 70 return Status::ok(); 71 } 72 73 if (checkCallingPermission(APPROVE_INCIDENT_REPORTS)) { 74 // Permission controller (this is a singleton permission that is always granted 75 // exactly for PermissionController) is allowed to access incident reports 76 // so it can show the user info about what they are approving. 77 return Status::ok(); 78 } 79 80 // checking calling permission. 81 if (!checkCallingPermission(DUMP_PERMISSION)) { 82 ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP", 83 callingPid, callingUid); 84 return Status::fromExceptionCode( 85 Status::EX_SECURITY, 86 "Calling process does not have permission: android.permission.DUMP"); 87 } 88 if (!checkCallingPermission(USAGE_STATS_PERMISSION)) { 89 ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS", 90 callingPid, callingUid); 91 return Status::fromExceptionCode( 92 Status::EX_SECURITY, 93 "Calling process does not have permission: android.permission.USAGE_STATS"); 94 } 95 96 // checking calling request uid permission. 97 switch (args.getPrivacyPolicy()) { 98 case PRIVACY_POLICY_LOCAL: 99 if (callingUid != AID_SHELL && callingUid != AID_ROOT) { 100 ALOGW("Calling pid %d and uid %d does not have permission to get local data.", 101 callingPid, callingUid); 102 return Status::fromExceptionCode( 103 Status::EX_SECURITY, 104 "Calling process does not have permission to get local data."); 105 } 106 break; 107 case PRIVACY_POLICY_EXPLICIT: 108 if (callingUid != AID_SHELL && callingUid != AID_ROOT && callingUid != AID_STATSD && 109 callingUid != AID_SYSTEM) { 110 ALOGW("Calling pid %d and uid %d does not have permission to get explicit data.", 111 callingPid, callingUid); 112 return Status::fromExceptionCode( 113 Status::EX_SECURITY, 114 "Calling process does not have permission to get explicit data."); 115 } 116 break; 117 } 118 return Status::ok(); 119 } 120 build_uri(const string & pkg,const string & cls,const string & id)121 static string build_uri(const string& pkg, const string& cls, const string& id) { 122 return "content://android.os.IncidentManager/pending?pkg=" 123 + pkg + "&receiver=" + cls + "&r=" + id; 124 } 125 126 // ================================================================================ ReportHandler(const sp<WorkDirectory> & workDirectory,const sp<Broadcaster> & broadcaster,const sp<Looper> & handlerLooper,const sp<Throttler> & throttler,const vector<BringYourOwnSection * > & registeredSections)127 ReportHandler::ReportHandler(const sp<WorkDirectory>& workDirectory, 128 const sp<Broadcaster>& broadcaster, 129 const sp<Looper>& handlerLooper, 130 const sp<Throttler>& throttler, 131 const vector<BringYourOwnSection*>& registeredSections) 132 :mLock(), 133 mWorkDirectory(workDirectory), 134 mBroadcaster(broadcaster), 135 mHandlerLooper(handlerLooper), 136 mBacklogDelay(DEFAULT_DELAY_NS), 137 mThrottler(throttler), 138 mRegisteredSections(registeredSections), 139 mBatch(new ReportBatch()) { 140 } 141 ~ReportHandler()142 ReportHandler::~ReportHandler() { 143 } 144 handleMessage(const Message & message)145 void ReportHandler::handleMessage(const Message& message) { 146 switch (message.what) { 147 case WHAT_TAKE_REPORT: 148 take_report(); 149 break; 150 case WHAT_SEND_BROADCASTS: 151 send_broadcasts(); 152 break; 153 } 154 } 155 schedulePersistedReport(const IncidentReportArgs & args)156 void ReportHandler::schedulePersistedReport(const IncidentReportArgs& args) { 157 unique_lock<mutex> lock(mLock); 158 mBatch->addPersistedReport(args); 159 mHandlerLooper->removeMessages(this, WHAT_TAKE_REPORT); 160 mHandlerLooper->sendMessage(this, Message(WHAT_TAKE_REPORT)); 161 } 162 scheduleStreamingReport(const IncidentReportArgs & args,const sp<IIncidentReportStatusListener> & listener,int streamFd)163 void ReportHandler::scheduleStreamingReport(const IncidentReportArgs& args, 164 const sp<IIncidentReportStatusListener>& listener, int streamFd) { 165 unique_lock<mutex> lock(mLock); 166 mBatch->addStreamingReport(args, listener, streamFd); 167 mHandlerLooper->removeMessages(this, WHAT_TAKE_REPORT); 168 mHandlerLooper->sendMessage(this, Message(WHAT_TAKE_REPORT)); 169 } 170 scheduleSendBacklog()171 void ReportHandler::scheduleSendBacklog() { 172 unique_lock<mutex> lock(mLock); 173 mBacklogDelay = DEFAULT_DELAY_NS; 174 schedule_send_broadcasts_locked(); 175 } 176 schedule_send_broadcasts_locked()177 void ReportHandler::schedule_send_broadcasts_locked() { 178 mHandlerLooper->removeMessages(this, WHAT_SEND_BROADCASTS); 179 mHandlerLooper->sendMessageDelayed(mBacklogDelay, this, Message(WHAT_SEND_BROADCASTS)); 180 } 181 take_report()182 void ReportHandler::take_report() { 183 // Cycle the batch and throttle. 184 sp<ReportBatch> batch; 185 { 186 unique_lock<mutex> lock(mLock); 187 batch = mThrottler->filterBatch(mBatch); 188 } 189 190 if (batch->empty()) { 191 // Nothing to do. 192 return; 193 } 194 195 sp<Reporter> reporter = new Reporter(mWorkDirectory, batch, mRegisteredSections); 196 197 // Take the report, which might take a while. More requests might queue 198 // up while we're doing this, and we'll handle them in their next batch. 199 // TODO: We should further rate-limit the reports to no more than N per time-period. 200 // TODO: Move this inside reporter. 201 size_t reportByteSize = 0; 202 reporter->runReport(&reportByteSize); 203 204 // Tell the throttler how big it was, for the next throttling. 205 // TODO: This still isn't ideal. The throttler really should just track the 206 // persisted reqeusts, but changing Reporter::runReport() to track that individually 207 // will be a big change. 208 if (batch->hasPersistedReports()) { 209 mThrottler->addReportSize(reportByteSize); 210 } 211 212 // Kick off the next steps, one of which is to send any new or otherwise remaining 213 // approvals, and one of which is to send any new or remaining broadcasts. 214 { 215 unique_lock<mutex> lock(mLock); 216 schedule_send_broadcasts_locked(); 217 } 218 } 219 send_broadcasts()220 void ReportHandler::send_broadcasts() { 221 Broadcaster::broadcast_status_t result = mBroadcaster->sendBroadcasts(); 222 if (result == Broadcaster::BROADCASTS_FINISHED) { 223 // We're done. 224 unique_lock<mutex> lock(mLock); 225 mBacklogDelay = DEFAULT_DELAY_NS; 226 } else if (result == Broadcaster::BROADCASTS_REPEAT) { 227 // It worked, but there are more. 228 unique_lock<mutex> lock(mLock); 229 mBacklogDelay = DEFAULT_DELAY_NS; 230 schedule_send_broadcasts_locked(); 231 } else if (result == Broadcaster::BROADCASTS_BACKOFF) { 232 // There was a failure. Exponential backoff. 233 unique_lock<mutex> lock(mLock); 234 mBacklogDelay *= 2; 235 ALOGI("Error sending to dropbox. Trying again in %lld minutes", 236 (mBacklogDelay / (1000000000LL * 60))); 237 schedule_send_broadcasts_locked(); 238 } 239 } 240 241 // ================================================================================ IncidentService(const sp<Looper> & handlerLooper)242 IncidentService::IncidentService(const sp<Looper>& handlerLooper) { 243 mThrottler = new Throttler(DEFAULT_BYTES_SIZE_LIMIT, DEFAULT_REFACTORY_PERIOD_MS); 244 mWorkDirectory = new WorkDirectory(); 245 mBroadcaster = new Broadcaster(mWorkDirectory); 246 mHandler = new ReportHandler(mWorkDirectory, mBroadcaster, handlerLooper, 247 mThrottler, mRegisteredSections); 248 mBroadcaster->setHandler(mHandler); 249 } 250 ~IncidentService()251 IncidentService::~IncidentService() {} 252 reportIncident(const IncidentReportArgs & args)253 Status IncidentService::reportIncident(const IncidentReportArgs& args) { 254 IncidentReportArgs argsCopy(args); 255 256 // Validate that the privacy policy is one of the real ones. 257 // If it isn't, clamp it to the next more restrictive real one. 258 argsCopy.setPrivacyPolicy(cleanup_privacy_policy(args.getPrivacyPolicy())); 259 260 // TODO: Check that the broadcast recevier has the proper permissions 261 // TODO: Maybe we should consider relaxing the permissions if it's going to 262 // dropbox, but definitely not if it's going to the broadcaster. 263 Status status = checkIncidentPermissions(args); 264 if (!status.isOk()) { 265 return status; 266 } 267 268 // If they asked for the LOCAL privacy policy, give them EXPLICT. LOCAL has to 269 // be streamed. (This only applies to shell/root, because everyone else would have 270 // been rejected by checkIncidentPermissions()). 271 if (argsCopy.getPrivacyPolicy() < PRIVACY_POLICY_EXPLICIT) { 272 ALOGI("Demoting privacy policy to EXPLICT for persisted report."); 273 argsCopy.setPrivacyPolicy(PRIVACY_POLICY_EXPLICIT); 274 } 275 276 // If they didn't specify a component, use dropbox. 277 if (argsCopy.receiverPkg().length() == 0 && argsCopy.receiverCls().length() == 0) { 278 argsCopy.setReceiverPkg(DROPBOX_SENTINEL.getPackageName()); 279 argsCopy.setReceiverCls(DROPBOX_SENTINEL.getClassName()); 280 } 281 282 mHandler->schedulePersistedReport(argsCopy); 283 284 return Status::ok(); 285 } 286 reportIncidentToStream(const IncidentReportArgs & args,const sp<IIncidentReportStatusListener> & listener,unique_fd stream)287 Status IncidentService::reportIncidentToStream(const IncidentReportArgs& args, 288 const sp<IIncidentReportStatusListener>& listener, 289 unique_fd stream) { 290 IncidentReportArgs argsCopy(args); 291 292 // Streaming reports can not also be broadcast. 293 argsCopy.setReceiverPkg(""); 294 argsCopy.setReceiverCls(""); 295 296 // Validate that the privacy policy is one of the real ones. 297 // If it isn't, clamp it to the next more restrictive real one. 298 argsCopy.setPrivacyPolicy(cleanup_privacy_policy(args.getPrivacyPolicy())); 299 300 Status status = checkIncidentPermissions(argsCopy); 301 if (!status.isOk()) { 302 return status; 303 } 304 305 // The ReportRequest takes ownership of the fd, so we need to dup it. 306 int fd = dup(stream.get()); 307 if (fd < 0) { 308 return Status::fromStatusT(-errno); 309 } 310 311 mHandler->scheduleStreamingReport(argsCopy, listener, fd); 312 313 return Status::ok(); 314 } 315 reportIncidentToDumpstate(unique_fd stream,const sp<IIncidentReportStatusListener> & listener)316 Status IncidentService::reportIncidentToDumpstate(unique_fd stream, 317 const sp<IIncidentReportStatusListener>& listener) { 318 uid_t caller = IPCThreadState::self()->getCallingUid(); 319 if (caller != AID_ROOT && caller != AID_SHELL) { 320 ALOGW("Calling uid %d does not have permission: only ROOT or SHELL allowed", caller); 321 return Status::fromExceptionCode(Status::EX_SECURITY, "Only ROOT or SHELL allowed"); 322 } 323 324 ALOGD("Stream incident report to dumpstate"); 325 IncidentReportArgs incidentArgs; 326 // Privacy policy for dumpstate incident reports is always EXPLICIT. 327 incidentArgs.setPrivacyPolicy(PRIVACY_POLICY_EXPLICIT); 328 329 int skipped[] = SKIPPED_DUMPSTATE_SECTIONS; 330 for (const Section** section = SECTION_LIST; *section; section++) { 331 const int id = (*section)->id; 332 if (std::find(std::begin(skipped), std::end(skipped), id) == std::end(skipped) 333 && !section_requires_specific_mention(id)) { 334 incidentArgs.addSection(id); 335 } 336 } 337 for (const Section* section : mRegisteredSections) { 338 if (!section_requires_specific_mention(section->id)) { 339 incidentArgs.addSection(section->id); 340 } 341 } 342 343 // The ReportRequest takes ownership of the fd, so we need to dup it. 344 int fd = dup(stream.get()); 345 if (fd < 0) { 346 return Status::fromStatusT(-errno); 347 } 348 349 mHandler->scheduleStreamingReport(incidentArgs, listener, fd); 350 351 return Status::ok(); 352 } 353 registerSection(const int id,const String16 & name16,const sp<IIncidentDumpCallback> & callback)354 Status IncidentService::registerSection(const int id, const String16& name16, 355 const sp<IIncidentDumpCallback>& callback) { 356 const String8 name = String8(name16); 357 const uid_t callingUid = IPCThreadState::self()->getCallingUid(); 358 ALOGI("Uid %d registers section %d '%s'", callingUid, id, name.c_str()); 359 if (callback == nullptr) { 360 return Status::fromExceptionCode(Status::EX_NULL_POINTER); 361 } 362 for (int i = 0; i < mRegisteredSections.size(); i++) { 363 if (mRegisteredSections.at(i)->id == id) { 364 if (mRegisteredSections.at(i)->uid != callingUid) { 365 ALOGW("Error registering section %d: calling uid does not match", id); 366 return Status::fromExceptionCode(Status::EX_SECURITY); 367 } 368 mRegisteredSections.at(i) = new BringYourOwnSection(id, name.c_str(), callingUid, callback); 369 return Status::ok(); 370 } 371 } 372 mRegisteredSections.push_back(new BringYourOwnSection(id, name.c_str(), callingUid, callback)); 373 return Status::ok(); 374 } 375 unregisterSection(const int id)376 Status IncidentService::unregisterSection(const int id) { 377 uid_t callingUid = IPCThreadState::self()->getCallingUid(); 378 ALOGI("Uid %d unregisters section %d", callingUid, id); 379 380 for (auto it = mRegisteredSections.begin(); it != mRegisteredSections.end(); it++) { 381 if ((*it)->id == id) { 382 if ((*it)->uid != callingUid) { 383 ALOGW("Error unregistering section %d: calling uid does not match", id); 384 return Status::fromExceptionCode(Status::EX_SECURITY); 385 } 386 mRegisteredSections.erase(it); 387 return Status::ok(); 388 } 389 } 390 ALOGW("Section %d not found", id); 391 return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); 392 } 393 systemRunning()394 Status IncidentService::systemRunning() { 395 if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) { 396 return Status::fromExceptionCode(Status::EX_SECURITY, 397 "Only system uid can call systemRunning"); 398 } 399 400 // When system_server is up and running, schedule the dropbox task to run. 401 mBroadcaster->reset(); 402 mHandler->scheduleSendBacklog(); 403 404 return Status::ok(); 405 } 406 getIncidentReportList(const String16 & pkg16,const String16 & cls16,vector<String16> * result)407 Status IncidentService::getIncidentReportList(const String16& pkg16, const String16& cls16, 408 vector<String16>* result) { 409 status_t err; 410 const string pkg(String8(pkg16).string()); 411 const string cls(String8(cls16).string()); 412 413 // List the reports 414 vector<sp<ReportFile>> all; 415 err = mWorkDirectory->getReports(&all, 0); 416 if (err != NO_ERROR) { 417 return Status::fromStatusT(err); 418 } 419 420 // Find the ones that match pkg and cls. 421 for (sp<ReportFile>& file: all) { 422 err = file->loadEnvelope(); 423 if (err != NO_ERROR) { 424 continue; 425 } 426 const ReportFileProto& envelope = file->getEnvelope(); 427 size_t reportCount = envelope.report_size(); 428 for (int reportIndex = 0; reportIndex < reportCount; reportIndex++) { 429 const ReportFileProto_Report& report = envelope.report(reportIndex); 430 if (pkg == report.pkg() && cls == report.cls()) { 431 result->push_back(String16(build_uri(pkg, cls, file->getId()).c_str())); 432 break; 433 } 434 } 435 } 436 437 return Status::ok(); 438 } 439 getIncidentReport(const String16 & pkg16,const String16 & cls16,const String16 & id16,IncidentManager::IncidentReport * result)440 Status IncidentService::getIncidentReport(const String16& pkg16, const String16& cls16, 441 const String16& id16, IncidentManager::IncidentReport* result) { 442 status_t err; 443 444 const string pkg(String8(pkg16).string()); 445 const string cls(String8(cls16).string()); 446 const string id(String8(id16).string()); 447 448 IncidentReportArgs args; 449 sp<ReportFile> file = mWorkDirectory->getReport(pkg, cls, id, &args); 450 if (file != nullptr) { 451 // Create pipe 452 int fds[2]; 453 if (pipe(fds) != 0) { 454 ALOGW("Error opening pipe to filter incident report: %s", 455 file->getDataFileName().c_str()); 456 return Status::ok(); 457 } 458 result->setTimestampNs(file->getTimestampNs()); 459 result->setPrivacyPolicy(file->getEnvelope().privacy_policy()); 460 result->takeFileDescriptor(fds[0]); 461 int writeFd = fds[1]; 462 // spawn a thread to write the data. Release the writeFd ownership to the thread. 463 thread th([file, writeFd, args]() { file->startFilteringData(writeFd, args); }); 464 465 th.detach(); 466 } 467 468 return Status::ok(); 469 } 470 deleteIncidentReports(const String16 & pkg16,const String16 & cls16,const String16 & id16)471 Status IncidentService::deleteIncidentReports(const String16& pkg16, const String16& cls16, 472 const String16& id16) { 473 const string pkg(String8(pkg16).string()); 474 const string cls(String8(cls16).string()); 475 const string id(String8(id16).string()); 476 477 sp<ReportFile> file = mWorkDirectory->getReport(pkg, cls, id, nullptr); 478 if (file != nullptr) { 479 mWorkDirectory->commit(file, pkg, cls); 480 } 481 mBroadcaster->clearBroadcasts(pkg, cls, id); 482 483 return Status::ok(); 484 } 485 deleteAllIncidentReports(const String16 & pkg16)486 Status IncidentService::deleteAllIncidentReports(const String16& pkg16) { 487 const string pkg(String8(pkg16).string()); 488 489 mWorkDirectory->commitAll(pkg); 490 mBroadcaster->clearPackageBroadcasts(pkg); 491 492 return Status::ok(); 493 } 494 495 /** 496 * Implement our own because the default binder implementation isn't 497 * properly handling SHELL_COMMAND_TRANSACTION. 498 */ onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)499 status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, 500 uint32_t flags) { 501 status_t err; 502 503 switch (code) { 504 case SHELL_COMMAND_TRANSACTION: { 505 unique_fd in, out, err; 506 if (status_t status = data.readUniqueFileDescriptor(&in); status != OK) return status; 507 508 if (status_t status = data.readUniqueFileDescriptor(&out); status != OK) return status; 509 510 if (status_t status = data.readUniqueFileDescriptor(&err); status != OK) return status; 511 512 int argc = data.readInt32(); 513 Vector<String8> args; 514 for (int i = 0; i < argc && data.dataAvail() > 0; i++) { 515 args.add(String8(data.readString16())); 516 } 517 sp<IShellCallback> shellCallback = IShellCallback::asInterface(data.readStrongBinder()); 518 sp<IResultReceiver> resultReceiver = 519 IResultReceiver::asInterface(data.readStrongBinder()); 520 521 FILE* fin = fdopen(in.release(), "r"); 522 FILE* fout = fdopen(out.release(), "w"); 523 FILE* ferr = fdopen(err.release(), "w"); 524 525 if (fin == NULL || fout == NULL || ferr == NULL) { 526 resultReceiver->send(NO_MEMORY); 527 } else { 528 status_t result = command(fin, fout, ferr, args); 529 resultReceiver->send(result); 530 } 531 532 if (fin != NULL) { 533 fflush(fin); 534 fclose(fin); 535 } 536 if (fout != NULL) { 537 fflush(fout); 538 fclose(fout); 539 } 540 if (fout != NULL) { 541 fflush(ferr); 542 fclose(ferr); 543 } 544 545 return NO_ERROR; 546 } break; 547 default: { return BnIncidentManager::onTransact(code, data, reply, flags); } 548 } 549 } 550 command(FILE * in,FILE * out,FILE * err,Vector<String8> & args)551 status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) { 552 const int argCount = args.size(); 553 554 if (argCount >= 1) { 555 if (!args[0].compare(String8("privacy"))) { 556 return cmd_privacy(in, out, err, args); 557 } 558 if (!args[0].compare(String8("throttler"))) { 559 mThrottler->dump(out); 560 return NO_ERROR; 561 } 562 if (!args[0].compare(String8("section"))) { 563 if (argCount == 1) { 564 fprintf(out, "Not enough arguments for section\n"); 565 return NO_ERROR; 566 } 567 int id = atoi(args[1]); 568 int idx = 0; 569 while (SECTION_LIST[idx] != NULL) { 570 const Section* section = SECTION_LIST[idx]; 571 if (section->id == id) { 572 fprintf(out, "Section[%d] %s\n", id, section->name.string()); 573 break; 574 } 575 idx++; 576 } 577 return NO_ERROR; 578 } 579 } 580 return cmd_help(out); 581 } 582 cmd_help(FILE * out)583 status_t IncidentService::cmd_help(FILE* out) { 584 fprintf(out, "usage: adb shell cmd incident privacy print <section_id>\n"); 585 fprintf(out, "usage: adb shell cmd incident privacy parse <section_id> < proto.txt\n"); 586 fprintf(out, " Prints/parses for the section id.\n\n"); 587 fprintf(out, "usage: adb shell cmd incident section <section_id>\n"); 588 fprintf(out, " Prints section id and its name.\n\n"); 589 fprintf(out, "usage: adb shell cmd incident throttler\n"); 590 fprintf(out, " Prints the current throttler state\n"); 591 return NO_ERROR; 592 } 593 printPrivacy(const Privacy * p,FILE * out,String8 indent)594 static void printPrivacy(const Privacy* p, FILE* out, String8 indent) { 595 if (p == NULL) return; 596 fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.string(), p->field_id, p->type, p->policy); 597 if (p->children == NULL) return; 598 for (int i = 0; p->children[i] != NULL; i++) { // NULL-terminated. 599 printPrivacy(p->children[i], out, indent + " "); 600 } 601 } 602 cmd_privacy(FILE * in,FILE * out,FILE * err,Vector<String8> & args)603 status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args) { 604 (void)in; 605 606 const int argCount = args.size(); 607 if (argCount >= 3) { 608 String8 opt = args[1]; 609 int sectionId = atoi(args[2].string()); 610 611 const Privacy* p = get_privacy_of_section(sectionId); 612 if (p == NULL) { 613 fprintf(err, "Can't find section id %d\n", sectionId); 614 return NO_ERROR; 615 } 616 fprintf(err, "Get privacy for %d\n", sectionId); 617 if (opt == "print") { 618 printPrivacy(p, out, String8("")); 619 } else if (opt == "parse") { 620 /* 621 FdBuffer buf; 622 status_t error = buf.read(fileno(in), 60000); 623 if (error != NO_ERROR) { 624 fprintf(err, "Error reading from stdin\n"); 625 return error; 626 } 627 fprintf(err, "Read %zu bytes\n", buf.size()); 628 PrivacyFilter pBuf(p, buf.data()); 629 630 PrivacySpec spec = PrivacySpec::new_spec(argCount > 3 ? atoi(args[3]) : -1); 631 error = pBuf.strip(spec); 632 if (error != NO_ERROR) { 633 fprintf(err, "Error strip pii fields with spec %d\n", spec.policy); 634 return error; 635 } 636 return pBuf.flush(fileno(out)); 637 */ 638 return -1; 639 } 640 } else { 641 return cmd_help(out); 642 } 643 return NO_ERROR; 644 } 645 646 } // namespace incidentd 647 } // namespace os 648 } // namespace android 649