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/procrank.proto.h"
21 #include "ih_util.h"
22 #include "ProcrankParser.h"
23 
24 using namespace android::os;
25 
26 status_t
Parse(const int in,const int out) const27 ProcrankParser::Parse(const int in, const int out) const
28 {
29     Reader reader(in);
30     string line;
31     header_t header;  // the header of /d/wakeup_sources
32     record_t record;  // retain each record
33     int nline = 0;
34 
35     ProtoOutputStream proto;
36     Table table(ProcrankProto::Process::_FIELD_NAMES, ProcrankProto::Process::_FIELD_IDS, ProcrankProto::Process::_FIELD_COUNT);
37     string zram, ram, total;
38 
39     // parse line by line
40     while (reader.readLine(&line)) {
41         if (line.empty()) continue;
42 
43         // parse head line
44         if (nline++ == 0) {
45             header = parseHeader(line);
46             continue;
47         }
48 
49         if (stripPrefix(&line, "ZRAM:")) {
50             zram = line;
51             continue;
52         }
53         if (stripPrefix(&line, "RAM:")) {
54             ram = line;
55             continue;
56         }
57 
58         record = parseRecord(line);
59         if (record.size() != header.size()) {
60             if (record[record.size() - 1] == "TOTAL") { // TOTAL record
61                 total = line;
62             } else {
63                 fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.c_str(), nline,
64                     line.c_str());
65             }
66             continue;
67         }
68 
69         uint64_t token = proto.start(ProcrankProto::PROCESSES);
70         for (int i=0; i<(int)record.size(); i++) {
71             if (!table.insertField(&proto, header[i], record[i])) {
72                 fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
73                         this->name.c_str(), nline, header[i].c_str(), record[i].c_str());
74             }
75         }
76         proto.end(token);
77     }
78 
79     // add summary
80     uint64_t token = proto.start(ProcrankProto::SUMMARY);
81     if (!total.empty()) {
82         record = parseRecord(total);
83         uint64_t token = proto.start(ProcrankProto::Summary::TOTAL);
84         for (int i=(int)record.size(); i>0; i--) {
85             table.insertField(&proto, header[header.size() - i].c_str(), record[record.size() - i].c_str());
86         }
87         proto.end(token);
88     }
89     if (!zram.empty()) {
90         uint64_t token = proto.start(ProcrankProto::Summary::ZRAM);
91         proto.write(ProcrankProto::Summary::Zram::RAW_TEXT, zram);
92         proto.end(token);
93     }
94     if (!ram.empty()) {
95         uint64_t token = proto.start(ProcrankProto::Summary::RAM);
96         proto.write(ProcrankProto::Summary::Ram::RAW_TEXT, ram);
97         proto.end(token);
98     }
99     proto.end(token);
100 
101     if (!reader.ok(&line)) {
102         fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
103         return -1;
104     }
105 
106     if (!proto.flush(out)) {
107         fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
108         return -1;
109     }
110     fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
111     return NO_ERROR;
112 }
113