1/* 2 * Copyright (C) 2017 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 LOG_TAG "incident_helper" 17 18#include <android/util/ProtoOutputStream.h> 19 20#include "frameworks/base/core/proto/android/os/ps.proto.h" 21#include "ih_util.h" 22#include "PsParser.h" 23 24using namespace android::os; 25 26status_t PsParser::Parse(const int in, const int out) const { 27 Reader reader(in); 28 string line; 29 header_t header; // the header of /d/wakeup_sources 30 vector<int> columnIndices; // task table can't be split by purely delimiter, needs column positions. 31 record_t record; // retain each record 32 int nline = 0; 33 int diff = 0; 34 35 ProtoOutputStream proto; 36 Table table(PsProto::Process::_FIELD_NAMES, PsProto::Process::_FIELD_IDS, PsProto::Process::_FIELD_COUNT); 37 const char* pcyNames[] = { "fg", "bg", "ta" }; 38 const int pcyValues[] = {PsProto::Process::POLICY_FG, PsProto::Process::POLICY_BG, PsProto::Process::POLICY_TA}; 39 table.addEnumTypeMap("pcy", pcyNames, pcyValues, 3); 40 const char* sNames[] = { "D", "R", "S", "T", "t", "X", "Z" }; 41 const int sValues[] = {PsProto::Process::STATE_D, PsProto::Process::STATE_R, PsProto::Process::STATE_S, PsProto::Process::STATE_T, PsProto::Process::STATE_TRACING, PsProto::Process::STATE_X, PsProto::Process::STATE_Z}; 42 table.addEnumTypeMap("s", sNames, sValues, 7); 43 44 // Parse line by line 45 while (reader.readLine(&line)) { 46 if (line.empty()) continue; 47 48 if (nline++ == 0) { 49 header = parseHeader(line, DEFAULT_WHITESPACE); 50 51 const char* headerNames[] = { "LABEL", "USER", "PID", "TID", "PPID", "VSZ", "RSS", "WCHAN", "ADDR", "S", "PRI", "NI", "RTPRIO", "SCH", "PCY", "TIME", "CMD", NULL }; 52 if (!getColumnIndices(columnIndices, headerNames, line)) { 53 return -1; 54 } 55 56 continue; 57 } 58 59 record = parseRecordByColumns(line, columnIndices); 60 61 diff = record.size() - header.size(); 62 if (diff < 0) { 63 // TODO: log this to incident report! 64 fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.string(), nline, -diff, line.c_str()); 65 printRecord(record); 66 continue; 67 } else if (diff > 0) { 68 // TODO: log this to incident report! 69 fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.string(), nline, diff, line.c_str()); 70 printRecord(record); 71 continue; 72 } 73 74 uint64_t token = proto.start(PsProto::PROCESSES); 75 for (int i=0; i<(int)record.size(); i++) { 76 if (!table.insertField(&proto, header[i], record[i])) { 77 fprintf(stderr, "[%s]Line %d has bad value %s of %s\n", 78 this->name.string(), nline, header[i].c_str(), record[i].c_str()); 79 } 80 } 81 proto.end(token); 82 } 83 84 if (!reader.ok(&line)) { 85 fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str()); 86 return -1; 87 } 88 89 if (!proto.flush(out)) { 90 fprintf(stderr, "[%s]Error writing proto back\n", this->name.string()); 91 return -1; 92 } 93 fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size()); 94 return NO_ERROR; 95} 96