1 /*
2  * Copyright (C) 2024 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 
17 #define LOG_TAG "pixelstats: BatteryTTFReporter"
18 
19 #include <android-base/file.h>
20 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
21 #include <log/log.h>
22 #include <pixelstats/BatteryTTFReporter.h>
23 #include <pixelstats/StatsHelper.h>
24 #include <time.h>
25 #include <utils/Timers.h>
26 
27 #include <cinttypes>
28 
29 namespace android {
30 namespace hardware {
31 namespace google {
32 namespace pixel {
33 
34 using aidl::android::frameworks::stats::IStats;
35 using aidl::android::frameworks::stats::VendorAtom;
36 using aidl::android::frameworks::stats::VendorAtomValue;
37 using android::base::ReadFileToString;
38 using android::base::WriteStringToFile;
39 using android::hardware::google::pixel::PixelAtoms::BatteryTimeToFullStatsReported;
40 
41 const int SECONDS_PER_MONTH = 60 * 60 * 24 * 30;
42 
BatteryTTFReporter()43 BatteryTTFReporter::BatteryTTFReporter() {}
44 
getTimeSecs(void)45 int64_t BatteryTTFReporter::getTimeSecs(void) {
46     return nanoseconds_to_seconds(systemTime(SYSTEM_TIME_BOOTTIME));
47 }
48 
reportBatteryTTFStats(const std::shared_ptr<IStats> & stats_client)49 bool BatteryTTFReporter::reportBatteryTTFStats(const std::shared_ptr<IStats> &stats_client) {
50     std::string path = kBatteryTTFPath;
51     std::string file_contents, line;
52     std::istringstream ss;
53 
54     if (!ReadFileToString(path.c_str(), &file_contents)) {
55         ALOGD("Unsupported path %s - %s", path.c_str(), strerror(errno));
56         return false;
57     }
58 
59     ss.str(file_contents);
60 
61     while (std::getline(ss, line)) {
62         reportBatteryTTFStatsEvent(stats_client, line.c_str());
63     }
64 
65     return true;
66 }
67 
reportBatteryTTFStatsEvent(const std::shared_ptr<IStats> & stats_client,const char * line)68 void BatteryTTFReporter::reportBatteryTTFStatsEvent(
69         const std::shared_ptr<IStats> &stats_client, const char *line) {
70     int ttf_stats_stats_fields[] = {
71         BatteryTimeToFullStatsReported::kTtfTypeFieldNumber,
72         BatteryTimeToFullStatsReported::kTtfRangeFieldNumber,
73         BatteryTimeToFullStatsReported::kSoc0FieldNumber,
74         BatteryTimeToFullStatsReported::kSoc1FieldNumber,
75         BatteryTimeToFullStatsReported::kSoc2FieldNumber,
76         BatteryTimeToFullStatsReported::kSoc3FieldNumber,
77         BatteryTimeToFullStatsReported::kSoc4FieldNumber,
78         BatteryTimeToFullStatsReported::kSoc5FieldNumber,
79         BatteryTimeToFullStatsReported::kSoc6FieldNumber,
80         BatteryTimeToFullStatsReported::kSoc7FieldNumber,
81         BatteryTimeToFullStatsReported::kSoc8FieldNumber,
82         BatteryTimeToFullStatsReported::kSoc9FieldNumber,
83     };
84 
85     const int32_t fields_size = std::size(ttf_stats_stats_fields);
86     const int32_t soc_start = 2; /* after type and range */
87     int32_t size, range, type, i = 0, soc[fields_size - soc_start] = { 0 };
88     std::vector<VendorAtomValue> values(fields_size);
89     VendorAtomValue val;
90     char ttf_type;
91 
92     size = sscanf(line, "%c%d:\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d",
93                   &ttf_type, &range, &soc[0], &soc[1], &soc[2], &soc[3],
94                   &soc[4], &soc[5], &soc[6], &soc[7], &soc[8], &soc[9]);
95 
96     if (size != fields_size)
97         return;
98 
99     if (ttf_type == 'T') /* Elap Time */
100         type = 0;
101     else if (ttf_type == 'C') /* Charge Counter */
102         type = 1;
103     else
104         return; /* Unknown */
105 
106     ALOGD("BatteryTTFStats: processed %s", line);
107     val.set<VendorAtomValue::intValue>(type);
108     values[ttf_stats_stats_fields[0] - kVendorAtomOffset] = val;
109     val.set<VendorAtomValue::intValue>(range);
110     values[ttf_stats_stats_fields[1] - kVendorAtomOffset] = val;
111     for (i = soc_start; i < fields_size; i++) {
112         val.set<VendorAtomValue::intValue>(soc[i - soc_start]);
113         values[ttf_stats_stats_fields[i] - kVendorAtomOffset] = val;
114     }
115 
116     VendorAtom event = {.reverseDomainName = "",
117                         .atomId = PixelAtoms::Atom::kBatteryTimeToFullStatsReported,
118                         .values = std::move(values)};
119     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
120     if (!ret.isOk())
121         ALOGE("Unable to report BatteryTTFStats to Stats service");
122 }
123 
checkAndReportStats(const std::shared_ptr<IStats> & stats_client)124 void BatteryTTFReporter::checkAndReportStats(const std::shared_ptr<IStats> &stats_client) {
125     int64_t now = getTimeSecs();
126     if ((report_time_ != 0) && (now - report_time_ < SECONDS_PER_MONTH)) {
127         ALOGD("Do not upload yet. now: %" PRId64 ", pre: %" PRId64, now, report_time_);
128         return;
129     }
130 
131     bool successStats = reportBatteryTTFStats(stats_client);
132 
133     if (successStats) {
134         report_time_ = now;
135     }
136 }
137 
138 }  // namespace pixel
139 }  // namespace google
140 }  // namespace hardware
141 }  // namespace android
142