diff options
Diffstat (limited to 'cmds/incidentd/src/IncidentService.cpp')
-rw-r--r-- | cmds/incidentd/src/IncidentService.cpp | 247 |
1 files changed, 169 insertions, 78 deletions
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index 1d5ab59f9ba8..9ae624094dca 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -13,15 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#define LOG_TAG "incidentd" +#include "Log.h" #include "IncidentService.h" +#include "FdBuffer.h" +#include "PrivacyBuffer.h" #include "Reporter.h" +#include "incidentd_util.h" +#include "section_list.h" #include <binder/IPCThreadState.h> +#include <binder/IResultReceiver.h> #include <binder/IServiceManager.h> +#include <binder/IShellCallback.h> #include <cutils/log.h> #include <private/android_filesystem_config.h> #include <utils/Looper.h> @@ -29,11 +34,9 @@ #include <unistd.h> using namespace android; +using namespace android::base; -enum { - WHAT_RUN_REPORT = 1, - WHAT_SEND_BACKLOG_TO_DROPBOX = 2 -}; +enum { WHAT_RUN_REPORT = 1, WHAT_SEND_BACKLOG_TO_DROPBOX = 2 }; //#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL * 60 * 5) #define DEFAULT_BACKLOG_DELAY_NS (1000000000LL) @@ -42,10 +45,9 @@ enum { String16 const DUMP_PERMISSION("android.permission.DUMP"); String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS"); -static Status -checkIncidentPermissions(const IncidentReportArgs& args) -{ +static Status checkIncidentPermissions(const IncidentReportArgs& args) { uid_t callingUid = IPCThreadState::self()->getCallingUid(); + pid_t callingPid = IPCThreadState::self()->getCallingPid(); if (callingUid == AID_ROOT || callingUid == AID_SHELL) { // root doesn't have permission.DUMP if don't do this! return Status::ok(); @@ -54,52 +56,52 @@ checkIncidentPermissions(const IncidentReportArgs& args) // checking calling permission. if (!checkCallingPermission(DUMP_PERMISSION)) { ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP", - IPCThreadState::self()->getCallingPid(), callingUid); - return Status::fromExceptionCode(Status::EX_SECURITY, + callingPid, callingUid); + return Status::fromExceptionCode( + Status::EX_SECURITY, "Calling process does not have permission: android.permission.DUMP"); } if (!checkCallingPermission(USAGE_STATS_PERMISSION)) { ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS", - IPCThreadState::self()->getCallingPid(), callingUid); - return Status::fromExceptionCode(Status::EX_SECURITY, + callingPid, callingUid); + return Status::fromExceptionCode( + Status::EX_SECURITY, "Calling process does not have permission: android.permission.USAGE_STATS"); } // checking calling request uid permission. switch (args.dest()) { case DEST_LOCAL: - if (callingUid != AID_SHELL || callingUid != AID_ROOT) { - return Status::fromExceptionCode(Status::EX_SECURITY, - "Calling process does not have permission to get local data."); + if (callingUid != AID_SHELL && callingUid != AID_ROOT) { + ALOGW("Calling pid %d and uid %d does not have permission to get local data.", + callingPid, callingUid); + return Status::fromExceptionCode( + Status::EX_SECURITY, + "Calling process does not have permission to get local data."); } case DEST_EXPLICIT: - if (callingUid != AID_SHELL || callingUid != AID_ROOT || - callingUid != AID_STATSD || callingUid != AID_SYSTEM) { - return Status::fromExceptionCode(Status::EX_SECURITY, - "Calling process does not have permission to get explicit data."); + if (callingUid != AID_SHELL && callingUid != AID_ROOT && callingUid != AID_STATSD && + callingUid != AID_SYSTEM) { + ALOGW("Calling pid %d and uid %d does not have permission to get explicit data.", + callingPid, callingUid); + return Status::fromExceptionCode( + Status::EX_SECURITY, + "Calling process does not have permission to get explicit data."); } } return Status::ok(); } // ================================================================================ -ReportRequestQueue::ReportRequestQueue() -{ -} +ReportRequestQueue::ReportRequestQueue() {} -ReportRequestQueue::~ReportRequestQueue() -{ -} +ReportRequestQueue::~ReportRequestQueue() {} -void -ReportRequestQueue::addRequest(const sp<ReportRequest>& request) -{ +void ReportRequestQueue::addRequest(const sp<ReportRequest>& request) { unique_lock<mutex> lock(mLock); mQueue.push_back(request); } -sp<ReportRequest> -ReportRequestQueue::getNextRequest() -{ +sp<ReportRequest> ReportRequestQueue::getNextRequest() { unique_lock<mutex> lock(mLock); if (mQueue.empty()) { return NULL; @@ -110,22 +112,13 @@ ReportRequestQueue::getNextRequest() } } - // ================================================================================ ReportHandler::ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue) - :mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS), - mHandlerLooper(handlerLooper), - mQueue(queue) -{ -} + : mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS), mHandlerLooper(handlerLooper), mQueue(queue) {} -ReportHandler::~ReportHandler() -{ -} +ReportHandler::~ReportHandler() {} -void -ReportHandler::handleMessage(const Message& message) -{ +void ReportHandler::handleMessage(const Message& message) { switch (message.what) { case WHAT_RUN_REPORT: run_report(); @@ -136,33 +129,24 @@ ReportHandler::handleMessage(const Message& message) } } -void -ReportHandler::scheduleRunReport(const sp<ReportRequest>& request) -{ +void ReportHandler::scheduleRunReport(const sp<ReportRequest>& request) { mQueue->addRequest(request); mHandlerLooper->removeMessages(this, WHAT_RUN_REPORT); mHandlerLooper->sendMessage(this, Message(WHAT_RUN_REPORT)); } -void -ReportHandler::scheduleSendBacklogToDropbox() -{ +void ReportHandler::scheduleSendBacklogToDropbox() { unique_lock<mutex> lock(mLock); mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS; schedule_send_backlog_to_dropbox_locked(); } -void -ReportHandler::schedule_send_backlog_to_dropbox_locked() -{ +void ReportHandler::schedule_send_backlog_to_dropbox_locked() { mHandlerLooper->removeMessages(this, WHAT_SEND_BACKLOG_TO_DROPBOX); - mHandlerLooper->sendMessageDelayed(mBacklogDelay, this, - Message(WHAT_SEND_BACKLOG_TO_DROPBOX)); + mHandlerLooper->sendMessageDelayed(mBacklogDelay, this, Message(WHAT_SEND_BACKLOG_TO_DROPBOX)); } -void -ReportHandler::run_report() -{ +void ReportHandler::run_report() { sp<Reporter> reporter = new Reporter(); // Merge all of the requests into one that has all of the @@ -185,15 +169,13 @@ ReportHandler::run_report() } } -void -ReportHandler::send_backlog_to_dropbox() -{ +void ReportHandler::send_backlog_to_dropbox() { if (Reporter::upload_backlog() == Reporter::REPORT_NEEDS_DROPBOX) { // There was a failure. Exponential backoff. unique_lock<mutex> lock(mLock); mBacklogDelay *= 2; ALOGI("Error sending to dropbox. Trying again in %lld minutes", - (mBacklogDelay / (1000000000LL * 60))); + (mBacklogDelay / (1000000000LL * 60))); schedule_send_backlog_to_dropbox_locked(); } else { mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS; @@ -202,18 +184,13 @@ ReportHandler::send_backlog_to_dropbox() // ================================================================================ IncidentService::IncidentService(const sp<Looper>& handlerLooper) - :mQueue(new ReportRequestQueue()) -{ + : mQueue(new ReportRequestQueue()) { mHandler = new ReportHandler(handlerLooper, mQueue); } -IncidentService::~IncidentService() -{ -} +IncidentService::~IncidentService() {} -Status -IncidentService::reportIncident(const IncidentReportArgs& args) -{ +Status IncidentService::reportIncident(const IncidentReportArgs& args) { ALOGI("reportIncident"); Status status = checkIncidentPermissions(args); @@ -226,10 +203,9 @@ IncidentService::reportIncident(const IncidentReportArgs& args) return Status::ok(); } -Status -IncidentService::reportIncidentToStream(const IncidentReportArgs& args, - const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream) -{ +Status IncidentService::reportIncidentToStream(const IncidentReportArgs& args, + const sp<IIncidentReportStatusListener>& listener, + const unique_fd& stream) { ALOGI("reportIncidentToStream"); Status status = checkIncidentPermissions(args); @@ -247,12 +223,10 @@ IncidentService::reportIncidentToStream(const IncidentReportArgs& args, return Status::ok(); } -Status -IncidentService::systemRunning() -{ +Status IncidentService::systemRunning() { if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) { return Status::fromExceptionCode(Status::EX_SECURITY, - "Only system uid can call systemRunning"); + "Only system uid can call systemRunning"); } // When system_server is up and running, schedule the dropbox task to run. @@ -261,3 +235,120 @@ IncidentService::systemRunning() return Status::ok(); } +/** + * Implement our own because the default binder implementation isn't + * properly handling SHELL_COMMAND_TRANSACTION. + */ +status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { + status_t err; + + switch (code) { + case SHELL_COMMAND_TRANSACTION: { + int in = data.readFileDescriptor(); + int out = data.readFileDescriptor(); + int err = data.readFileDescriptor(); + int argc = data.readInt32(); + Vector<String8> args; + for (int i = 0; i < argc && data.dataAvail() > 0; i++) { + args.add(String8(data.readString16())); + } + sp<IShellCallback> shellCallback = IShellCallback::asInterface(data.readStrongBinder()); + sp<IResultReceiver> resultReceiver = + IResultReceiver::asInterface(data.readStrongBinder()); + + FILE* fin = fdopen(in, "r"); + FILE* fout = fdopen(out, "w"); + FILE* ferr = fdopen(err, "w"); + + if (fin == NULL || fout == NULL || ferr == NULL) { + resultReceiver->send(NO_MEMORY); + } else { + err = command(fin, fout, ferr, args); + resultReceiver->send(err); + } + + if (fin != NULL) { + fflush(fin); + fclose(fin); + } + if (fout != NULL) { + fflush(fout); + fclose(fout); + } + if (fout != NULL) { + fflush(ferr); + fclose(ferr); + } + + return NO_ERROR; + } + default: { return BnIncidentManager::onTransact(code, data, reply, flags); } + } +} + +status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) { + const int argCount = args.size(); + + if (argCount >= 1) { + if (!args[0].compare(String8("privacy"))) { + return cmd_privacy(in, out, err, args); + } + } + return cmd_help(out); +} + +status_t IncidentService::cmd_help(FILE* out) { + fprintf(out, "usage: adb shell cmd incident privacy print <section_id>\n"); + fprintf(out, "usage: adb shell cmd incident privacy parse <section_id> < proto.txt\n"); + fprintf(out, " Prints/parses for the section id.\n"); + return NO_ERROR; +} + +static void printPrivacy(const Privacy* p, FILE* out, String8 indent) { + if (p == NULL) return; + fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.string(), p->field_id, p->type, p->dest); + if (p->children == NULL) return; + for (int i = 0; p->children[i] != NULL; i++) { // NULL-terminated. + printPrivacy(p->children[i], out, indent + " "); + } +} + +status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args) { + const int argCount = args.size(); + if (argCount >= 3) { + String8 opt = args[1]; + int sectionId = atoi(args[2].string()); + + const Privacy* p = get_privacy_of_section(sectionId); + if (p == NULL) { + fprintf(err, "Can't find section id %d\n", sectionId); + return NO_ERROR; + } + fprintf(err, "Get privacy for %d\n", sectionId); + if (opt == "print") { + printPrivacy(p, out, String8("")); + } else if (opt == "parse") { + FdBuffer buf; + status_t error = buf.read(fileno(in), 60000); + if (error != NO_ERROR) { + fprintf(err, "Error reading from stdin\n"); + return error; + } + fprintf(err, "Read %zu bytes\n", buf.size()); + auto data = buf.data(); + PrivacyBuffer pBuf(p, data); + + PrivacySpec spec = PrivacySpec::new_spec(argCount > 3 ? atoi(args[3]) : -1); + error = pBuf.strip(spec); + if (error != NO_ERROR) { + fprintf(err, "Error strip pii fields with spec %d\n", spec.dest); + return error; + } + return pBuf.flush(fileno(out)); + } + } else { + return cmd_help(out); + } + return NO_ERROR; +} |