1947fbce521d9e8377df03e3c1c31884ed5577f32yro/*
2947fbce521d9e8377df03e3c1c31884ed5577f32yro * Copyright (C) 2017 The Android Open Source Project
3947fbce521d9e8377df03e3c1c31884ed5577f32yro *
4947fbce521d9e8377df03e3c1c31884ed5577f32yro * Licensed under the Apache License, Version 2.0 (the "License");
5947fbce521d9e8377df03e3c1c31884ed5577f32yro * you may not use this file except in compliance with the License.
6947fbce521d9e8377df03e3c1c31884ed5577f32yro * You may obtain a copy of the License at
7947fbce521d9e8377df03e3c1c31884ed5577f32yro *
8947fbce521d9e8377df03e3c1c31884ed5577f32yro *      http://www.apache.org/licenses/LICENSE-2.0
9947fbce521d9e8377df03e3c1c31884ed5577f32yro *
10947fbce521d9e8377df03e3c1c31884ed5577f32yro * Unless required by applicable law or agreed to in writing, software
11947fbce521d9e8377df03e3c1c31884ed5577f32yro * distributed under the License is distributed on an "AS IS" BASIS,
12947fbce521d9e8377df03e3c1c31884ed5577f32yro * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13947fbce521d9e8377df03e3c1c31884ed5577f32yro * See the License for the specific language governing permissions and
14947fbce521d9e8377df03e3c1c31884ed5577f32yro * limitations under the License.
15947fbce521d9e8377df03e3c1c31884ed5577f32yro */
16947fbce521d9e8377df03e3c1c31884ed5577f32yro
17484524a246ffe453f8cd89b698a279c23b0bde1fTej Singh#define DEBUG false  // STOPSHIP if true
18947fbce521d9e8377df03e3c1c31884ed5577f32yro#include "Log.h"
19947fbce521d9e8377df03e3c1c31884ed5577f32yro
20947fbce521d9e8377df03e3c1c31884ed5577f32yro#include "android-base/stringprintf.h"
2198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro#include "guardrail/StatsdStats.h"
2298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro#include "storage/StorageManager.h"
23330af58f2b8582b855085655fae553cdfaf44e6cYangster-mac#include "stats_log_util.h"
24947fbce521d9e8377df03e3c1c31884ed5577f32yro
25947fbce521d9e8377df03e3c1c31884ed5577f32yro#include <android-base/file.h>
26947fbce521d9e8377df03e3c1c31884ed5577f32yro#include <dirent.h>
2798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro#include <private/android_filesystem_config.h>
2898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro#include <fstream>
2998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro#include <iostream>
30947fbce521d9e8377df03e3c1c31884ed5577f32yro
31947fbce521d9e8377df03e3c1c31884ed5577f32yronamespace android {
32947fbce521d9e8377df03e3c1c31884ed5577f32yronamespace os {
33947fbce521d9e8377df03e3c1c31884ed5577f32yronamespace statsd {
34947fbce521d9e8377df03e3c1c31884ed5577f32yro
35f09569f848ca0b81a21a74e9f4dd8bd9a886151aYao Chenusing android::util::FIELD_COUNT_REPEATED;
36f09569f848ca0b81a21a74e9f4dd8bd9a886151aYao Chenusing android::util::FIELD_TYPE_MESSAGE;
37f09569f848ca0b81a21a74e9f4dd8bd9a886151aYao Chenusing std::map;
38f09569f848ca0b81a21a74e9f4dd8bd9a886151aYao Chen
3998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro#define STATS_DATA_DIR "/data/misc/stats-data"
4003faf093301847f0ac293ce8d6fcb0bce657a841yro#define STATS_SERVICE_DIR "/data/misc/stats-service"
41947fbce521d9e8377df03e3c1c31884ed5577f32yro
42947fbce521d9e8377df03e3c1c31884ed5577f32yro// for ConfigMetricsReportList
43947fbce521d9e8377df03e3c1c31884ed5577f32yroconst int FIELD_ID_REPORTS = 2;
44947fbce521d9e8377df03e3c1c31884ed5577f32yro
45947fbce521d9e8377df03e3c1c31884ed5577f32yrousing android::base::StringPrintf;
46947fbce521d9e8377df03e3c1c31884ed5577f32yrousing std::unique_ptr;
47947fbce521d9e8377df03e3c1c31884ed5577f32yro
4898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro// Returns array of int64_t which contains timestamp in seconds, uid, and
4998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro// configID.
5098a28501fe8ab53a490ec353c8a1f74f2e329cc5yrostatic void parseFileName(char* name, int64_t* result) {
5198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    int index = 0;
5298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    char* substr = strtok(name, "_");
5398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    while (substr != nullptr && index < 3) {
5498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        result[index] = StrToInt64(substr);
5598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        index++;
5698a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        substr = strtok(nullptr, "_");
5798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    }
5898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    // When index ends before hitting 3, file name is corrupted. We
5998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    // intentionally put -1 at index 0 to indicate the error to caller.
6098a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    // TODO: consider removing files with unexpected name format.
6198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    if (index < 3) {
6298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        result[0] = -1;
6398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    }
6498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro}
6598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
6698a28501fe8ab53a490ec353c8a1f74f2e329cc5yrostatic string getFilePath(const char* path, int64_t timestamp, int64_t uid, int64_t configID) {
6750d23f1ed57003a389c010e3445bbc33b7c74a83yro    return StringPrintf("%s/%lld_%d_%lld", path, (long long)timestamp, (int)uid,
6898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro                        (long long)configID);
6998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro}
7098a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
71947fbce521d9e8377df03e3c1c31884ed5577f32yrovoid StorageManager::writeFile(const char* file, const void* buffer, int numBytes) {
72947fbce521d9e8377df03e3c1c31884ed5577f32yro    int fd = open(file, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
73c7bdc6291df427f2de9ba191246065f5ff87e11fStefan Lafon    if (fd == -1) {
74947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("Attempt to access %s but failed", file);
75947fbce521d9e8377df03e3c1c31884ed5577f32yro        return;
76947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
7798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    trimToFit(STATS_SERVICE_DIR);
7898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    trimToFit(STATS_DATA_DIR);
79947fbce521d9e8377df03e3c1c31884ed5577f32yro
80947fbce521d9e8377df03e3c1c31884ed5577f32yro    int result = write(fd, buffer, numBytes);
81947fbce521d9e8377df03e3c1c31884ed5577f32yro    if (result == numBytes) {
82947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("Successfully wrote %s", file);
83947fbce521d9e8377df03e3c1c31884ed5577f32yro    } else {
84947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("Failed to write %s", file);
85947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
8698a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
8798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    result = fchown(fd, AID_STATSD, AID_STATSD);
8898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    if (result) {
8998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        VLOG("Failed to chown %s to statsd", file);
9098a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    }
9198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
92947fbce521d9e8377df03e3c1c31884ed5577f32yro    close(fd);
93947fbce521d9e8377df03e3c1c31884ed5577f32yro}
94947fbce521d9e8377df03e3c1c31884ed5577f32yro
95947fbce521d9e8377df03e3c1c31884ed5577f32yrovoid StorageManager::deleteFile(const char* file) {
96947fbce521d9e8377df03e3c1c31884ed5577f32yro    if (remove(file) != 0) {
97947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("Attempt to delete %s but is not found", file);
98947fbce521d9e8377df03e3c1c31884ed5577f32yro    } else {
99947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("Successfully deleted %s", file);
100947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
101947fbce521d9e8377df03e3c1c31884ed5577f32yro}
102947fbce521d9e8377df03e3c1c31884ed5577f32yro
103947fbce521d9e8377df03e3c1c31884ed5577f32yrovoid StorageManager::deleteAllFiles(const char* path) {
104947fbce521d9e8377df03e3c1c31884ed5577f32yro    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
105947fbce521d9e8377df03e3c1c31884ed5577f32yro    if (dir == NULL) {
106947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("Directory does not exist: %s", path);
107947fbce521d9e8377df03e3c1c31884ed5577f32yro        return;
108947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
109947fbce521d9e8377df03e3c1c31884ed5577f32yro
110947fbce521d9e8377df03e3c1c31884ed5577f32yro    dirent* de;
111947fbce521d9e8377df03e3c1c31884ed5577f32yro    while ((de = readdir(dir.get()))) {
112947fbce521d9e8377df03e3c1c31884ed5577f32yro        char* name = de->d_name;
113947fbce521d9e8377df03e3c1c31884ed5577f32yro        if (name[0] == '.') continue;
114947fbce521d9e8377df03e3c1c31884ed5577f32yro        deleteFile(StringPrintf("%s/%s", path, name).c_str());
115947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
116947fbce521d9e8377df03e3c1c31884ed5577f32yro}
117947fbce521d9e8377df03e3c1c31884ed5577f32yro
118e5f82927ae60fdff909e030434354a6ba164f333yrovoid StorageManager::deleteSuffixedFiles(const char* path, const char* suffix) {
119947fbce521d9e8377df03e3c1c31884ed5577f32yro    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
120947fbce521d9e8377df03e3c1c31884ed5577f32yro    if (dir == NULL) {
121947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("Directory does not exist: %s", path);
122947fbce521d9e8377df03e3c1c31884ed5577f32yro        return;
123947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
124947fbce521d9e8377df03e3c1c31884ed5577f32yro
125947fbce521d9e8377df03e3c1c31884ed5577f32yro    dirent* de;
126947fbce521d9e8377df03e3c1c31884ed5577f32yro    while ((de = readdir(dir.get()))) {
127947fbce521d9e8377df03e3c1c31884ed5577f32yro        char* name = de->d_name;
128e5f82927ae60fdff909e030434354a6ba164f333yro        if (name[0] == '.') {
129947fbce521d9e8377df03e3c1c31884ed5577f32yro            continue;
130947fbce521d9e8377df03e3c1c31884ed5577f32yro        }
131e5f82927ae60fdff909e030434354a6ba164f333yro        size_t nameLen = strlen(name);
132e5f82927ae60fdff909e030434354a6ba164f333yro        size_t suffixLen = strlen(suffix);
133e5f82927ae60fdff909e030434354a6ba164f333yro        if (suffixLen <= nameLen && strncmp(name + nameLen - suffixLen, suffix, suffixLen) == 0) {
134e5f82927ae60fdff909e030434354a6ba164f333yro            deleteFile(StringPrintf("%s/%s", path, name).c_str());
135e5f82927ae60fdff909e030434354a6ba164f333yro        }
136947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
137947fbce521d9e8377df03e3c1c31884ed5577f32yro}
138947fbce521d9e8377df03e3c1c31884ed5577f32yro
139947fbce521d9e8377df03e3c1c31884ed5577f32yrovoid StorageManager::sendBroadcast(const char* path,
140947fbce521d9e8377df03e3c1c31884ed5577f32yro                                   const std::function<void(const ConfigKey&)>& sendBroadcast) {
141947fbce521d9e8377df03e3c1c31884ed5577f32yro    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
142947fbce521d9e8377df03e3c1c31884ed5577f32yro    if (dir == NULL) {
143947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("no stats-data directory on disk");
144947fbce521d9e8377df03e3c1c31884ed5577f32yro        return;
145947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
146947fbce521d9e8377df03e3c1c31884ed5577f32yro
147947fbce521d9e8377df03e3c1c31884ed5577f32yro    dirent* de;
148947fbce521d9e8377df03e3c1c31884ed5577f32yro    while ((de = readdir(dir.get()))) {
149947fbce521d9e8377df03e3c1c31884ed5577f32yro        char* name = de->d_name;
150947fbce521d9e8377df03e3c1c31884ed5577f32yro        if (name[0] == '.') continue;
151947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("file %s", name);
152947fbce521d9e8377df03e3c1c31884ed5577f32yro
15398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t result[3];
15498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        parseFileName(name, result);
15598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        if (result[0] == -1) continue;
15698a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t uid = result[1];
15798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t configID = result[2];
158947fbce521d9e8377df03e3c1c31884ed5577f32yro
15998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        sendBroadcast(ConfigKey((int)uid, configID));
160947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
161947fbce521d9e8377df03e3c1c31884ed5577f32yro}
162947fbce521d9e8377df03e3c1c31884ed5577f32yro
16348944901f7e6334724efadda6c6b27d9e88fc9e2David Chenbool StorageManager::hasConfigMetricsReport(const ConfigKey& key) {
16448944901f7e6334724efadda6c6b27d9e88fc9e2David Chen    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_DATA_DIR), closedir);
16548944901f7e6334724efadda6c6b27d9e88fc9e2David Chen    if (dir == NULL) {
16648944901f7e6334724efadda6c6b27d9e88fc9e2David Chen        VLOG("Path %s does not exist", STATS_DATA_DIR);
16748944901f7e6334724efadda6c6b27d9e88fc9e2David Chen        return false;
16848944901f7e6334724efadda6c6b27d9e88fc9e2David Chen    }
16948944901f7e6334724efadda6c6b27d9e88fc9e2David Chen
17048944901f7e6334724efadda6c6b27d9e88fc9e2David Chen    string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
17148944901f7e6334724efadda6c6b27d9e88fc9e2David Chen
17248944901f7e6334724efadda6c6b27d9e88fc9e2David Chen    dirent* de;
17348944901f7e6334724efadda6c6b27d9e88fc9e2David Chen    while ((de = readdir(dir.get()))) {
17448944901f7e6334724efadda6c6b27d9e88fc9e2David Chen        char* name = de->d_name;
17548944901f7e6334724efadda6c6b27d9e88fc9e2David Chen        if (name[0] == '.') continue;
17648944901f7e6334724efadda6c6b27d9e88fc9e2David Chen
17748944901f7e6334724efadda6c6b27d9e88fc9e2David Chen        size_t nameLen = strlen(name);
17848944901f7e6334724efadda6c6b27d9e88fc9e2David Chen        size_t suffixLen = suffix.length();
17948944901f7e6334724efadda6c6b27d9e88fc9e2David Chen        if (suffixLen <= nameLen &&
18048944901f7e6334724efadda6c6b27d9e88fc9e2David Chen            strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) {
18148944901f7e6334724efadda6c6b27d9e88fc9e2David Chen            // Check again that the file name is parseable.
18248944901f7e6334724efadda6c6b27d9e88fc9e2David Chen            int64_t result[3];
18348944901f7e6334724efadda6c6b27d9e88fc9e2David Chen            parseFileName(name, result);
18448944901f7e6334724efadda6c6b27d9e88fc9e2David Chen            if (result[0] == -1) continue;
18548944901f7e6334724efadda6c6b27d9e88fc9e2David Chen            return true;
18648944901f7e6334724efadda6c6b27d9e88fc9e2David Chen        }
18748944901f7e6334724efadda6c6b27d9e88fc9e2David Chen    }
18848944901f7e6334724efadda6c6b27d9e88fc9e2David Chen    return false;
18948944901f7e6334724efadda6c6b27d9e88fc9e2David Chen}
19048944901f7e6334724efadda6c6b27d9e88fc9e2David Chen
1914beccbe3de7537365856bbd2a34be8d6f226b8b8yrovoid StorageManager::appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto) {
19298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_DATA_DIR), closedir);
1937250622b47397bd05983aa5655f18fb5cc757cb4Yao Chen    if (dir == NULL) {
19498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        VLOG("Path %s does not exist", STATS_DATA_DIR);
195947fbce521d9e8377df03e3c1c31884ed5577f32yro        return;
196947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
197947fbce521d9e8377df03e3c1c31884ed5577f32yro
198fef48cb64c505664b078818455baebbe3cc025cbYao Chen    string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
1994beccbe3de7537365856bbd2a34be8d6f226b8b8yro
200947fbce521d9e8377df03e3c1c31884ed5577f32yro    dirent* de;
201947fbce521d9e8377df03e3c1c31884ed5577f32yro    while ((de = readdir(dir.get()))) {
202947fbce521d9e8377df03e3c1c31884ed5577f32yro        char* name = de->d_name;
203947fbce521d9e8377df03e3c1c31884ed5577f32yro        if (name[0] == '.') continue;
204947fbce521d9e8377df03e3c1c31884ed5577f32yro
2054beccbe3de7537365856bbd2a34be8d6f226b8b8yro        size_t nameLen = strlen(name);
206fef48cb64c505664b078818455baebbe3cc025cbYao Chen        size_t suffixLen = suffix.length();
2074beccbe3de7537365856bbd2a34be8d6f226b8b8yro        if (suffixLen <= nameLen &&
208fef48cb64c505664b078818455baebbe3cc025cbYao Chen            strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) {
2094beccbe3de7537365856bbd2a34be8d6f226b8b8yro            int64_t result[3];
2104beccbe3de7537365856bbd2a34be8d6f226b8b8yro            parseFileName(name, result);
2114beccbe3de7537365856bbd2a34be8d6f226b8b8yro            if (result[0] == -1) continue;
2124beccbe3de7537365856bbd2a34be8d6f226b8b8yro            int64_t timestamp = result[0];
2134beccbe3de7537365856bbd2a34be8d6f226b8b8yro            int64_t uid = result[1];
2144beccbe3de7537365856bbd2a34be8d6f226b8b8yro            int64_t configID = result[2];
2154beccbe3de7537365856bbd2a34be8d6f226b8b8yro
2164beccbe3de7537365856bbd2a34be8d6f226b8b8yro            string file_name = getFilePath(STATS_DATA_DIR, timestamp, uid, configID);
2174beccbe3de7537365856bbd2a34be8d6f226b8b8yro            int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
2184beccbe3de7537365856bbd2a34be8d6f226b8b8yro            if (fd != -1) {
2194beccbe3de7537365856bbd2a34be8d6f226b8b8yro                string content;
2204beccbe3de7537365856bbd2a34be8d6f226b8b8yro                if (android::base::ReadFdToString(fd, &content)) {
2214beccbe3de7537365856bbd2a34be8d6f226b8b8yro                    proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
2224beccbe3de7537365856bbd2a34be8d6f226b8b8yro                                content.c_str(), content.size());
2234beccbe3de7537365856bbd2a34be8d6f226b8b8yro                }
2244beccbe3de7537365856bbd2a34be8d6f226b8b8yro                close(fd);
225947fbce521d9e8377df03e3c1c31884ed5577f32yro            }
226947fbce521d9e8377df03e3c1c31884ed5577f32yro
2274beccbe3de7537365856bbd2a34be8d6f226b8b8yro            // Remove file from disk after reading.
2284beccbe3de7537365856bbd2a34be8d6f226b8b8yro            remove(file_name.c_str());
2294beccbe3de7537365856bbd2a34be8d6f226b8b8yro        }
230947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
231947fbce521d9e8377df03e3c1c31884ed5577f32yro}
232947fbce521d9e8377df03e3c1c31884ed5577f32yro
233932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-macbool StorageManager::readFileToString(const char* file, string* content) {
234932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac    int fd = open(file, O_RDONLY | O_CLOEXEC);
235932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac    bool res = false;
236932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac    if (fd != -1) {
237932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac        if (android::base::ReadFdToString(fd, content)) {
238932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac            res = true;
239932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac        } else {
240932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac            VLOG("Failed to read file %s\n", file);
241932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac        }
242932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac        close(fd);
243932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac    }
244932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac    return res;
245932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac}
246932ececa1674c59a8da9f3e32d2651e781b86fc4Yangster-mac
247f09569f848ca0b81a21a74e9f4dd8bd9a886151aYao Chenvoid StorageManager::readConfigFromDisk(map<ConfigKey, StatsdConfig>& configsMap) {
248947fbce521d9e8377df03e3c1c31884ed5577f32yro    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
249947fbce521d9e8377df03e3c1c31884ed5577f32yro    if (dir == NULL) {
250947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("no default config on disk");
251947fbce521d9e8377df03e3c1c31884ed5577f32yro        return;
252947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
25398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    trimToFit(STATS_SERVICE_DIR);
254947fbce521d9e8377df03e3c1c31884ed5577f32yro
255947fbce521d9e8377df03e3c1c31884ed5577f32yro    dirent* de;
256947fbce521d9e8377df03e3c1c31884ed5577f32yro    while ((de = readdir(dir.get()))) {
257947fbce521d9e8377df03e3c1c31884ed5577f32yro        char* name = de->d_name;
258947fbce521d9e8377df03e3c1c31884ed5577f32yro        if (name[0] == '.') continue;
259947fbce521d9e8377df03e3c1c31884ed5577f32yro        VLOG("file %s", name);
260947fbce521d9e8377df03e3c1c31884ed5577f32yro
26198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t result[3];
26298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        parseFileName(name, result);
26398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        if (result[0] == -1) continue;
26498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t timestamp = result[0];
26598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t uid = result[1];
26698a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t configID = result[2];
26798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        string file_name = getFilePath(STATS_SERVICE_DIR, timestamp, uid, configID);
268947fbce521d9e8377df03e3c1c31884ed5577f32yro        int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
269947fbce521d9e8377df03e3c1c31884ed5577f32yro        if (fd != -1) {
270947fbce521d9e8377df03e3c1c31884ed5577f32yro            string content;
271947fbce521d9e8377df03e3c1c31884ed5577f32yro            if (android::base::ReadFdToString(fd, &content)) {
272947fbce521d9e8377df03e3c1c31884ed5577f32yro                StatsdConfig config;
273947fbce521d9e8377df03e3c1c31884ed5577f32yro                if (config.ParseFromString(content)) {
2746e304ec6901484157b9cae1cafc5713a825720bcyro                    configsMap[ConfigKey(uid, configID)] = config;
27598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro                    VLOG("map key uid=%lld|configID=%lld", (long long)uid, (long long)configID);
276947fbce521d9e8377df03e3c1c31884ed5577f32yro                }
277947fbce521d9e8377df03e3c1c31884ed5577f32yro            }
278947fbce521d9e8377df03e3c1c31884ed5577f32yro            close(fd);
279947fbce521d9e8377df03e3c1c31884ed5577f32yro        }
280947fbce521d9e8377df03e3c1c31884ed5577f32yro    }
281947fbce521d9e8377df03e3c1c31884ed5577f32yro}
282947fbce521d9e8377df03e3c1c31884ed5577f32yro
283b142cc8add29c8c97f6134d35873d23db666027cYangster-macbool StorageManager::readConfigFromDisk(const ConfigKey& key, StatsdConfig* config) {
284b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    string content;
285b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    return config != nullptr &&
286b142cc8add29c8c97f6134d35873d23db666027cYangster-mac        StorageManager::readConfigFromDisk(key, &content) && config->ParseFromString(content);
287b142cc8add29c8c97f6134d35873d23db666027cYangster-mac}
288b142cc8add29c8c97f6134d35873d23db666027cYangster-mac
289b142cc8add29c8c97f6134d35873d23db666027cYangster-macbool StorageManager::readConfigFromDisk(const ConfigKey& key, string* content) {
2904490765d1552f1a2ae114f9c301386823b930828yro    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR),
2914490765d1552f1a2ae114f9c301386823b930828yro                                             closedir);
2924490765d1552f1a2ae114f9c301386823b930828yro    if (dir == NULL) {
2934490765d1552f1a2ae114f9c301386823b930828yro        VLOG("Directory does not exist: %s", STATS_SERVICE_DIR);
2944490765d1552f1a2ae114f9c301386823b930828yro        return false;
2954490765d1552f1a2ae114f9c301386823b930828yro    }
2964490765d1552f1a2ae114f9c301386823b930828yro
297fef48cb64c505664b078818455baebbe3cc025cbYao Chen    string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
2984490765d1552f1a2ae114f9c301386823b930828yro    dirent* de;
2994490765d1552f1a2ae114f9c301386823b930828yro    while ((de = readdir(dir.get()))) {
3004490765d1552f1a2ae114f9c301386823b930828yro        char* name = de->d_name;
3014490765d1552f1a2ae114f9c301386823b930828yro        if (name[0] == '.') {
3024490765d1552f1a2ae114f9c301386823b930828yro            continue;
3034490765d1552f1a2ae114f9c301386823b930828yro        }
3044490765d1552f1a2ae114f9c301386823b930828yro        size_t nameLen = strlen(name);
305fef48cb64c505664b078818455baebbe3cc025cbYao Chen        size_t suffixLen = suffix.length();
3064490765d1552f1a2ae114f9c301386823b930828yro        // There can be at most one file that matches this suffix (config key).
3074490765d1552f1a2ae114f9c301386823b930828yro        if (suffixLen <= nameLen &&
308fef48cb64c505664b078818455baebbe3cc025cbYao Chen            strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) {
3094490765d1552f1a2ae114f9c301386823b930828yro            int fd = open(StringPrintf("%s/%s", STATS_SERVICE_DIR, name).c_str(),
3104490765d1552f1a2ae114f9c301386823b930828yro                                  O_RDONLY | O_CLOEXEC);
3114490765d1552f1a2ae114f9c301386823b930828yro            if (fd != -1) {
312b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                if (android::base::ReadFdToString(fd, content)) {
313b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                    return true;
3144490765d1552f1a2ae114f9c301386823b930828yro                }
3154beccbe3de7537365856bbd2a34be8d6f226b8b8yro                close(fd);
3164490765d1552f1a2ae114f9c301386823b930828yro            }
3174490765d1552f1a2ae114f9c301386823b930828yro        }
3184490765d1552f1a2ae114f9c301386823b930828yro    }
3194490765d1552f1a2ae114f9c301386823b930828yro    return false;
3204490765d1552f1a2ae114f9c301386823b930828yro}
3214490765d1552f1a2ae114f9c301386823b930828yro
322b142cc8add29c8c97f6134d35873d23db666027cYangster-macbool StorageManager::hasIdenticalConfig(const ConfigKey& key,
323b142cc8add29c8c97f6134d35873d23db666027cYangster-mac                                        const vector<uint8_t>& config) {
324b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    string content;
325b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    if (StorageManager::readConfigFromDisk(key, &content)) {
326b142cc8add29c8c97f6134d35873d23db666027cYangster-mac        vector<uint8_t> vec(content.begin(), content.end());
327b142cc8add29c8c97f6134d35873d23db666027cYangster-mac        if (vec == config) {
328b142cc8add29c8c97f6134d35873d23db666027cYangster-mac            return true;
329b142cc8add29c8c97f6134d35873d23db666027cYangster-mac        }
330b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    }
331b142cc8add29c8c97f6134d35873d23db666027cYangster-mac    return false;
332b142cc8add29c8c97f6134d35873d23db666027cYangster-mac}
333b142cc8add29c8c97f6134d35873d23db666027cYangster-mac
33498a28501fe8ab53a490ec353c8a1f74f2e329cc5yrovoid StorageManager::trimToFit(const char* path) {
33598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
33698a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    if (dir == NULL) {
33798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        VLOG("Path %s does not exist", path);
33898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        return;
33998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    }
34098a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    dirent* de;
34198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    int totalFileSize = 0;
34298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    vector<string> fileNames;
34398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    while ((de = readdir(dir.get()))) {
34498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        char* name = de->d_name;
34598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        if (name[0] == '.') continue;
34698a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
34798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t result[3];
34898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        parseFileName(name, result);
34998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        if (result[0] == -1) continue;
35098a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t timestamp = result[0];
35198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t uid = result[1];
35298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        int64_t configID = result[2];
35398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        string file_name = getFilePath(path, timestamp, uid, configID);
35498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
35598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        // Check for timestamp and delete if it's too old.
356330af58f2b8582b855085655fae553cdfaf44e6cYangster-mac        long fileAge = getWallClockSec() - timestamp;
35798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        if (fileAge > StatsdStats::kMaxAgeSecond) {
35898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro            deleteFile(file_name.c_str());
35998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        }
36098a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
36198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        fileNames.push_back(file_name);
36298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
36398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        if (file.is_open()) {
36498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro            file.seekg(0, ios::end);
36598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro            int fileSize = file.tellg();
36698a28501fe8ab53a490ec353c8a1f74f2e329cc5yro            file.close();
36798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro            totalFileSize += fileSize;
36898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        }
36998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    }
37098a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
37198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    if (fileNames.size() > StatsdStats::kMaxFileNumber ||
37298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        totalFileSize > StatsdStats::kMaxFileSize) {
37398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        // Reverse sort to effectively remove from the back (oldest entries).
37498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        // This will sort files in reverse-chronological order.
37598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        sort(fileNames.begin(), fileNames.end(), std::greater<std::string>());
37698a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    }
37798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
37898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    // Start removing files from oldest to be under the limit.
37998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    while (fileNames.size() > 0 && (fileNames.size() > StatsdStats::kMaxFileNumber ||
38098a28501fe8ab53a490ec353c8a1f74f2e329cc5yro                                    totalFileSize > StatsdStats::kMaxFileSize)) {
38198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        string file_name = fileNames.at(fileNames.size() - 1);
38298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
38398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        if (file.is_open()) {
38498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro            file.seekg(0, ios::end);
38598a28501fe8ab53a490ec353c8a1f74f2e329cc5yro            int fileSize = file.tellg();
38698a28501fe8ab53a490ec353c8a1f74f2e329cc5yro            file.close();
38798a28501fe8ab53a490ec353c8a1f74f2e329cc5yro            totalFileSize -= fileSize;
38898a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        }
38998a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
39098a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        deleteFile(file_name.c_str());
39198a28501fe8ab53a490ec353c8a1f74f2e329cc5yro        fileNames.pop_back();
39298a28501fe8ab53a490ec353c8a1f74f2e329cc5yro    }
39398a28501fe8ab53a490ec353c8a1f74f2e329cc5yro}
39498a28501fe8ab53a490ec353c8a1f74f2e329cc5yro
395665208d74345d779bed8724862e8d0d1c46a7a76yrovoid StorageManager::printStats(FILE* out) {
396665208d74345d779bed8724862e8d0d1c46a7a76yro    printDirStats(out, STATS_SERVICE_DIR);
397665208d74345d779bed8724862e8d0d1c46a7a76yro    printDirStats(out, STATS_DATA_DIR);
398665208d74345d779bed8724862e8d0d1c46a7a76yro}
399665208d74345d779bed8724862e8d0d1c46a7a76yro
400665208d74345d779bed8724862e8d0d1c46a7a76yrovoid StorageManager::printDirStats(FILE* out, const char* path) {
401665208d74345d779bed8724862e8d0d1c46a7a76yro    fprintf(out, "Printing stats of %s\n", path);
402665208d74345d779bed8724862e8d0d1c46a7a76yro    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
403665208d74345d779bed8724862e8d0d1c46a7a76yro    if (dir == NULL) {
404665208d74345d779bed8724862e8d0d1c46a7a76yro        VLOG("Path %s does not exist", path);
405665208d74345d779bed8724862e8d0d1c46a7a76yro        return;
406665208d74345d779bed8724862e8d0d1c46a7a76yro    }
407665208d74345d779bed8724862e8d0d1c46a7a76yro    dirent* de;
408665208d74345d779bed8724862e8d0d1c46a7a76yro    int fileCount = 0;
409665208d74345d779bed8724862e8d0d1c46a7a76yro    int totalFileSize = 0;
410665208d74345d779bed8724862e8d0d1c46a7a76yro    while ((de = readdir(dir.get()))) {
411665208d74345d779bed8724862e8d0d1c46a7a76yro        char* name = de->d_name;
412665208d74345d779bed8724862e8d0d1c46a7a76yro        if (name[0] == '.') {
413665208d74345d779bed8724862e8d0d1c46a7a76yro            continue;
414665208d74345d779bed8724862e8d0d1c46a7a76yro        }
415665208d74345d779bed8724862e8d0d1c46a7a76yro        int64_t result[3];
416665208d74345d779bed8724862e8d0d1c46a7a76yro        parseFileName(name, result);
417665208d74345d779bed8724862e8d0d1c46a7a76yro        if (result[0] == -1) continue;
418665208d74345d779bed8724862e8d0d1c46a7a76yro        int64_t timestamp = result[0];
419665208d74345d779bed8724862e8d0d1c46a7a76yro        int64_t uid = result[1];
420665208d74345d779bed8724862e8d0d1c46a7a76yro        int64_t configID = result[2];
421665208d74345d779bed8724862e8d0d1c46a7a76yro        fprintf(out, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld",
422665208d74345d779bed8724862e8d0d1c46a7a76yro                fileCount + 1,
423665208d74345d779bed8724862e8d0d1c46a7a76yro                (long long)timestamp,
424665208d74345d779bed8724862e8d0d1c46a7a76yro                (int)uid,
425665208d74345d779bed8724862e8d0d1c46a7a76yro                (long long)configID);
426665208d74345d779bed8724862e8d0d1c46a7a76yro        string file_name = getFilePath(path, timestamp, uid, configID);
427665208d74345d779bed8724862e8d0d1c46a7a76yro        ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
428665208d74345d779bed8724862e8d0d1c46a7a76yro        if (file.is_open()) {
429665208d74345d779bed8724862e8d0d1c46a7a76yro            file.seekg(0, ios::end);
430665208d74345d779bed8724862e8d0d1c46a7a76yro            int fileSize = file.tellg();
431665208d74345d779bed8724862e8d0d1c46a7a76yro            file.close();
432665208d74345d779bed8724862e8d0d1c46a7a76yro            fprintf(out, ", File Size: %d bytes", fileSize);
433665208d74345d779bed8724862e8d0d1c46a7a76yro            totalFileSize += fileSize;
434665208d74345d779bed8724862e8d0d1c46a7a76yro        }
435665208d74345d779bed8724862e8d0d1c46a7a76yro        fprintf(out, "\n");
436665208d74345d779bed8724862e8d0d1c46a7a76yro        fileCount++;
437665208d74345d779bed8724862e8d0d1c46a7a76yro    }
438665208d74345d779bed8724862e8d0d1c46a7a76yro    fprintf(out, "\tTotal number of files: %d, Total size of files: %d bytes.\n",
439665208d74345d779bed8724862e8d0d1c46a7a76yro            fileCount, totalFileSize);
440665208d74345d779bed8724862e8d0d1c46a7a76yro}
441665208d74345d779bed8724862e8d0d1c46a7a76yro
442947fbce521d9e8377df03e3c1c31884ed5577f32yro}  // namespace statsd
443947fbce521d9e8377df03e3c1c31884ed5577f32yro}  // namespace os
444947fbce521d9e8377df03e3c1c31884ed5577f32yro}  // namespace android
445