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).c_str());
411     const string cls(String8(cls16).c_str());
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).c_str());
445     const string cls(String8(cls16).c_str());
446     const string id(String8(id16).c_str());
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).c_str());
474     const string cls(String8(cls16).c_str());
475     const string id(String8(id16).c_str());
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).c_str());
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             if (resultReceiver == nullptr) {
521                 return BAD_VALUE;
522             }
523 
524             FILE* fin = fdopen(in.release(), "r");
525             FILE* fout = fdopen(out.release(), "w");
526             FILE* ferr = fdopen(err.release(), "w");
527 
528             if (fin == NULL || fout == NULL || ferr == NULL) {
529                 resultReceiver->send(NO_MEMORY);
530             } else {
531                 status_t result = command(fin, fout, ferr, args);
532                 resultReceiver->send(result);
533             }
534 
535             if (fin != NULL) {
536                 fflush(fin);
537                 fclose(fin);
538             }
539             if (fout != NULL) {
540                 fflush(fout);
541                 fclose(fout);
542             }
543             if (ferr != NULL) {
544                 fflush(ferr);
545                 fclose(ferr);
546             }
547 
548             return NO_ERROR;
549         } break;
550         default: { return BnIncidentManager::onTransact(code, data, reply, flags); }
551     }
552 }
553 
command(FILE * in,FILE * out,FILE * err,Vector<String8> & args)554 status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
555     const int argCount = args.size();
556 
557     if (argCount >= 1) {
558         if (!args[0].compare(String8("privacy"))) {
559             return cmd_privacy(in, out, err, args);
560         }
561         if (!args[0].compare(String8("throttler"))) {
562             mThrottler->dump(out);
563             return NO_ERROR;
564         }
565         if (!args[0].compare(String8("section"))) {
566             if (argCount == 1) {
567                 fprintf(out, "Not enough arguments for section\n");
568                 return NO_ERROR;
569             }
570             int id = atoi(args[1].c_str());
571             int idx = 0;
572             while (SECTION_LIST[idx] != NULL) {
573                 const Section* section = SECTION_LIST[idx];
574                 if (section->id == id) {
575                     fprintf(out, "Section[%d] %s\n", id, section->name.c_str());
576                     break;
577                 }
578                 idx++;
579             }
580             return NO_ERROR;
581         }
582     }
583     return cmd_help(out);
584 }
585 
cmd_help(FILE * out)586 status_t IncidentService::cmd_help(FILE* out) {
587     fprintf(out, "usage: adb shell cmd incident privacy print <section_id>\n");
588     fprintf(out, "usage: adb shell cmd incident privacy parse <section_id> < proto.txt\n");
589     fprintf(out, "    Prints/parses for the section id.\n\n");
590     fprintf(out, "usage: adb shell cmd incident section <section_id>\n");
591     fprintf(out, "    Prints section id and its name.\n\n");
592     fprintf(out, "usage: adb shell cmd incident throttler\n");
593     fprintf(out, "    Prints the current throttler state\n");
594     return NO_ERROR;
595 }
596 
printPrivacy(const Privacy * p,FILE * out,String8 indent)597 static void printPrivacy(const Privacy* p, FILE* out, String8 indent) {
598     if (p == NULL) return;
599     fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.c_str(), p->field_id, p->type, p->policy);
600     if (p->children == NULL) return;
601     for (int i = 0; p->children[i] != NULL; i++) {  // NULL-terminated.
602         printPrivacy(p->children[i], out, indent + "  ");
603     }
604 }
605 
cmd_privacy(FILE * in,FILE * out,FILE * err,Vector<String8> & args)606 status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
607     (void)in;
608 
609     const int argCount = args.size();
610     if (argCount >= 3) {
611         String8 opt = args[1];
612         int sectionId = atoi(args[2].c_str());
613 
614         const Privacy* p = get_privacy_of_section(sectionId);
615         if (p == NULL) {
616             fprintf(err, "Can't find section id %d\n", sectionId);
617             return NO_ERROR;
618         }
619         fprintf(err, "Get privacy for %d\n", sectionId);
620         if (opt == "print") {
621             printPrivacy(p, out, String8(""));
622         } else if (opt == "parse") {
623             /*
624             FdBuffer buf;
625             status_t error = buf.read(fileno(in), 60000);
626             if (error != NO_ERROR) {
627                 fprintf(err, "Error reading from stdin\n");
628                 return error;
629             }
630             fprintf(err, "Read %zu bytes\n", buf.size());
631             PrivacyFilter pBuf(p, buf.data());
632 
633             PrivacySpec spec = PrivacySpec::new_spec(argCount > 3 ? atoi(args[3]) : -1);
634             error = pBuf.strip(spec);
635             if (error != NO_ERROR) {
636                 fprintf(err, "Error strip pii fields with spec %d\n", spec.policy);
637                 return error;
638             }
639             return pBuf.flush(fileno(out));
640             */
641             return -1;
642         }
643     } else {
644         return cmd_help(out);
645     }
646     return NO_ERROR;
647 }
648 
649 }  // namespace incidentd
650 }  // namespace os
651 }  // namespace android
652