blob: 187f4ada61ca20c8e4af568ec6bdb5627cbc79f1 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android/os/DropBoxManager.h>
#include <android-base/file.h>
#include <cutils/log.h>
#include <androidfw/ZipUtils.h>
#include <stdio.h>
#include "DropboxReader.h"
using android::sp;
using android::String16;
using android::binder::Status;
using android::base::unique_fd;
using android::os::DropBoxManager;
using android::os::statsd::StatsLogEntry;
using android::ZipUtils;
using std::vector;
status_t DropboxReader::readStatsLogs(FILE* out, const string& tag, long msec) {
sp<DropBoxManager> dropbox = new DropBoxManager();
StatsLogList logList;
long timestamp = msec;
// instead of while(true), put a hard limit 1000. Dropbox won't have more than 1000 files.
for(int i = 0; i < 1000; i++ ) {
DropBoxManager::Entry entry;
Status status = dropbox->getNextEntry(String16(tag.c_str()),
timestamp, &entry);
if (!status.isOk()) {
ALOGD("No more entries, or failed to read. We can't tell unfortunately.");
return android::OK;
}
const unique_fd& fd = entry.getFd();
// use this timestamp for next query.
timestamp = entry.getTimestamp();
if (entry.getFlags() & DropBoxManager::IS_GZIPPED) {
if (!parseFromGzipFile(fd, logList)) {
// Failed to parse from the file. Continue to fetch the next entry.
continue;
}
} else {
if (!parseFromFile(fd, logList)) {
// Failed to parse from the file. Continue to fetch the next entry.
continue;
}
}
printLog(out, logList);
}
return android::OK;
}
bool DropboxReader::parseFromGzipFile(const unique_fd& fd, StatsLogList& list) {
FILE *file = fdopen(fd, "r");
bool result = false;
bool scanResult;
int method;
long compressedLen;
long uncompressedLen;
unsigned long crc32;
scanResult = ZipUtils::examineGzip(file, &method, &uncompressedLen,
&compressedLen, &crc32);
if (scanResult && method == kCompressDeflated) {
vector<uint8_t> buf(uncompressedLen);
if (ZipUtils::inflateToBuffer(file, &buf[0], uncompressedLen, compressedLen)) {
if (list.ParseFromArray(&buf[0], uncompressedLen)) {
result = true;
}
}
} else {
ALOGE("This isn't a valid deflated gzip file");
}
fclose(file);
return result;
}
// parse a non zipped file.
bool DropboxReader::parseFromFile(const unique_fd& fd, StatsLogList& list) {
string content;
if (!android::base::ReadFdToString(fd, &content)) {
ALOGE("Failed to read file");
return false;
}
if (!list.ParseFromString(content)) {
ALOGE("failed to parse log entry from data");
return false;
}
return true;
}
void DropboxReader::printLog(FILE* out, const StatsLogList& list) {
for (int i = 0; i < list.stats_log_entry_size(); i++) {
const StatsLogEntry entry = list.stats_log_entry(i);
// TODO: print pretty
fprintf(out, "time_msec=%lld, type=%d, aggregate_type=%d, uid=%d, pid=%d ",
entry.start_report_millis(), entry.type(), entry.aggregate_type(),
entry.uid(), entry.pid());
for (int j = 0; j < entry.pairs_size(); j++) {
fprintf(out, "msg=%s ", entry.pairs(j).value_str().c_str());
}
fprintf(out, "\n");
}
}