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