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