blob: 187f4ada61ca20c8e4af568ec6bdb5627cbc79f1 [file] [log] [blame]
Yao Chen482d2722017-09-12 13:25:43 -07001/*
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#include <android/os/DropBoxManager.h>
17#include <android-base/file.h>
18#include <cutils/log.h>
19#include <androidfw/ZipUtils.h>
20#include <stdio.h>
21
22#include "DropboxReader.h"
23
24using android::sp;
25using android::String16;
26using android::binder::Status;
27using android::base::unique_fd;
28using android::os::DropBoxManager;
29using android::os::statsd::StatsLogEntry;
30using android::ZipUtils;
31using std::vector;
32
33status_t DropboxReader::readStatsLogs(FILE* out, const string& tag, long msec) {
34 sp<DropBoxManager> dropbox = new DropBoxManager();
35 StatsLogList logList;
36
37 long timestamp = msec;
38 // instead of while(true), put a hard limit 1000. Dropbox won't have more than 1000 files.
39 for(int i = 0; i < 1000; i++ ) {
40 DropBoxManager::Entry entry;
41 Status status = dropbox->getNextEntry(String16(tag.c_str()),
42 timestamp, &entry);
43 if (!status.isOk()) {
44 ALOGD("No more entries, or failed to read. We can't tell unfortunately.");
45 return android::OK;
46 }
47
48 const unique_fd& fd = entry.getFd();
49
50 // use this timestamp for next query.
51 timestamp = entry.getTimestamp();
52
53 if (entry.getFlags() & DropBoxManager::IS_GZIPPED) {
54 if (!parseFromGzipFile(fd, logList)) {
55 // Failed to parse from the file. Continue to fetch the next entry.
56 continue;
57 }
58 } else {
59 if (!parseFromFile(fd, logList)) {
60 // Failed to parse from the file. Continue to fetch the next entry.
61 continue;
62 }
63 }
64
65 printLog(out, logList);
66 }
67 return android::OK;
68}
69
70bool DropboxReader::parseFromGzipFile(const unique_fd& fd, StatsLogList& list) {
71 FILE *file = fdopen(fd, "r");
72 bool result = false;
73 bool scanResult;
74 int method;
75 long compressedLen;
76 long uncompressedLen;
77 unsigned long crc32;
78 scanResult = ZipUtils::examineGzip(file, &method, &uncompressedLen,
79 &compressedLen, &crc32);
80 if (scanResult && method == kCompressDeflated) {
81 vector<uint8_t> buf(uncompressedLen);
82 if (ZipUtils::inflateToBuffer(file, &buf[0], uncompressedLen, compressedLen)) {
83 if (list.ParseFromArray(&buf[0], uncompressedLen)) {
84 result = true;
85 }
86 }
87 } else {
88 ALOGE("This isn't a valid deflated gzip file");
89 }
90 fclose(file);
91 return result;
92}
93
94// parse a non zipped file.
95bool DropboxReader::parseFromFile(const unique_fd& fd, StatsLogList& list) {
96 string content;
97 if (!android::base::ReadFdToString(fd, &content)) {
98 ALOGE("Failed to read file");
99 return false;
100 }
101 if (!list.ParseFromString(content)) {
102 ALOGE("failed to parse log entry from data");
103 return false;
104 }
105 return true;
106}
107
108void DropboxReader::printLog(FILE* out, const StatsLogList& list) {
109 for (int i = 0; i < list.stats_log_entry_size(); i++) {
110 const StatsLogEntry entry = list.stats_log_entry(i);
111 // TODO: print pretty
112 fprintf(out, "time_msec=%lld, type=%d, aggregate_type=%d, uid=%d, pid=%d ",
113 entry.start_report_millis(), entry.type(), entry.aggregate_type(),
114 entry.uid(), entry.pid());
115 for (int j = 0; j < entry.pairs_size(); j++) {
116 fprintf(out, "msg=%s ", entry.pairs(j).value_str().c_str());
117 }
118 fprintf(out, "\n");
119 }
120}