1 /*
2 * Copyright (C) 2020 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 #include <dataproviders/IioEnergyMeterDataSelector.h>
18
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/stringprintf.h>
22 #include <android-base/strings.h>
23 #include <inttypes.h>
24
25 namespace aidl {
26 namespace android {
27 namespace hardware {
28 namespace power {
29 namespace stats {
30
parseConfigData(const std::string data,std::unordered_map<std::string,std::list<std::string>> * deviceConfigs)31 void IioEnergyMeterDataSelector::parseConfigData(
32 const std::string data,
33 std::unordered_map<std::string, std::list<std::string>> *deviceConfigs) {
34 std::string deviceName; /* Initialized empty */
35 std::list<std::string> deviceConfig;
36
37 /* Parse the configuration from the config file */
38 std::istringstream input(data);
39 std::string line;
40 while (std::getline(input, line)) {
41 /* Skip whitespace/tab lines */
42 if (line.find_first_not_of("\t ") == std::string::npos) {
43 continue;
44 }
45
46 /* Look for "[Device Name]" in the line */
47 std::vector<std::string> words = ::android::base::Split(line, "][");
48 if (words.size() == 3) {
49 if (deviceName.empty() == false) {
50 /* End of device config - store config in map */
51 deviceConfigs->emplace(deviceName, deviceConfig);
52 deviceConfig.clear();
53 }
54
55 deviceName = words[1];
56 } else {
57 if (deviceName.empty() == false) {
58 /* We current have a device name set, store the line */
59 deviceConfig.emplace_back(line);
60 } /* Else skip line - no device name is yet associated with config line */
61 }
62 }
63
64 /* End of file - store config in map */
65 if (deviceName.empty() == false) {
66 deviceConfigs->emplace(deviceName, deviceConfig);
67 }
68 }
69
applyConfigToDevices(const std::unordered_map<std::string,std::list<std::string>> & deviceConfigs)70 void IioEnergyMeterDataSelector::applyConfigToDevices(
71 const std::unordered_map<std::string, std::list<std::string>> &deviceConfigs) {
72 for (const auto &devicePathPair : kDevicePaths) {
73 std::string devicePath = devicePathPair.first;
74 std::string deviceName = devicePathPair.second;
75
76 /* Check if a config exists for this device */
77 if (deviceConfigs.count(deviceName) == 1) {
78 LOG(INFO) << "Attempting to configure: " << deviceName;
79 std::string nodePath = devicePath + kSelectionNode;
80 std::list<std::string> config = deviceConfigs.at(deviceName);
81 for (const auto &railConfig : config) {
82 bool success = ::android::base::WriteStringToFile(railConfig, nodePath);
83 if (!success) {
84 LOG(ERROR) << "Failed to write: " << railConfig << " to: " << nodePath;
85 } else {
86 LOG(INFO) << "Wrote rail config: " << railConfig;
87 }
88 }
89 }
90 }
91 }
92
applyConfigsByAscendingPriority()93 void IioEnergyMeterDataSelector::applyConfigsByAscendingPriority() {
94 std::string data;
95
96 /* Parsed in order of initialization. Thus, the last item will have highest priority */
97 for (const auto &configPath : kConfigPaths) {
98 if (!::android::base::ReadFileToString(configPath, &data)) {
99 LOG(DEBUG) << "Could not parse rail config from " << configPath;
100 continue;
101 }
102
103 /* key: device name, value: list of config lines */
104 std::unordered_map<std::string, std::list<std::string>> deviceConfigs;
105 parseConfigData(data, &deviceConfigs);
106 applyConfigToDevices(deviceConfigs);
107 }
108 }
109
110 /**
111 * Sends configuration complete to the driver
112 */
sendConfigurationComplete()113 void IioEnergyMeterDataSelector::sendConfigurationComplete() {
114 for (const auto &devicePathPair : kDevicePaths) {
115 /* Sends configuration complete to the driver */
116 std::string devicePath = devicePathPair.first;
117 std::string nodePath = devicePath + kSelectionNode;
118 bool success = ::android::base::WriteStringToFile(kSelectionComplete, nodePath);
119 if (!success) {
120 LOG(ERROR) << "Failed to write: " << kSelectionComplete << " to: " << nodePath;
121 }
122 }
123 }
124
IioEnergyMeterDataSelector(const std::unordered_map<std::string,std::string> & devicePaths)125 IioEnergyMeterDataSelector::IioEnergyMeterDataSelector(
126 const std::unordered_map<std::string, std::string> &devicePaths)
127 : kDevicePaths(std::move(devicePaths)) {
128 applyConfigsByAscendingPriority();
129 sendConfigurationComplete();
130 }
131
132 } // namespace stats
133 } // namespace power
134 } // namespace hardware
135 } // namespace android
136 } // namespace aidl
137