• 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  #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