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 #include "host/commands/modem_simulator/nvram_config.h"
17
18 #include <android-base/logging.h>
19 #include <json/json.h>
20
21 #include <fstream>
22 #include <mutex>
23 #include <sstream>
24
25 #include "common/libs/utils/files.h"
26 #include "host/commands/modem_simulator/device_config.h"
27
28 namespace cuttlefish {
29
30 const char* kInstances = "instances";
31 const char* kNetworkSelectionMode = "network_selection_mode";
32 const char* kOperatorNumeric = "operator_numeric";
33 const char* kModemTechnoloy = "modem_technoloy";
34 const char* kPreferredNetworkMode = "preferred_network_mode";
35 const char* kEmergencyMode = "emergency_mode";
36
37 const int kDefaultNetworkSelectionMode = 0; // AUTOMATIC
38 const std::string kDefaultOperatorNumeric = "";
39 const int kDefaultModemTechnoloy = 0x10; // LTE
40 const int kDefaultPreferredNetworkMode = 0x13; // LTE | WCDMA | GSM
41 const bool kDefaultEmergencyMode = false;
42
43 /**
44 * Creates the (initially empty) config object and populates it with values from
45 * the config file "modem_nvram.json" located in the cuttlefish instance path,
46 * or uses the default value if the config file not exists,
47 * Returns nullptr if there was an error loading from file
48 */
BuildConfigImpl(size_t num_instances)49 NvramConfig* NvramConfig::BuildConfigImpl(size_t num_instances) {
50 auto nvram_config_path =
51 cuttlefish::modem::DeviceConfig::PerInstancePath("modem_nvram.json");
52
53 auto ret = new NvramConfig(num_instances);
54 if (ret) {
55 if (!cuttlefish::FileExists(nvram_config_path) ||
56 !cuttlefish::FileHasContent(nvram_config_path.c_str())) {
57 ret->InitDefaultNvramConfig();
58 } else {
59 auto loaded = ret->LoadFromFile(nvram_config_path.c_str());
60 if (!loaded) {
61 delete ret;
62 return nullptr;
63 }
64 }
65 }
66 return ret;
67 }
68
69 std::unique_ptr<NvramConfig> NvramConfig::s_nvram_config;
70
InitNvramConfigService(size_t num_instances)71 void NvramConfig::InitNvramConfigService(size_t num_instances) {
72 static std::once_flag once_flag;
73
74 std::call_once(once_flag, [num_instances]() {
75 NvramConfig::s_nvram_config.reset(BuildConfigImpl(num_instances));
76 });
77 }
78
Get()79 /* static */ const NvramConfig* NvramConfig::Get() {
80 return s_nvram_config.get();
81 }
82
SaveToFile()83 void NvramConfig::SaveToFile() {
84 auto nvram_config = Get();
85 auto nvram_config_file = nvram_config->ConfigFileLocation();
86 nvram_config->SaveToFile(nvram_config_file);
87 }
88
NvramConfig(size_t num_instances)89 NvramConfig::NvramConfig(size_t num_instances)
90 : total_instances_(num_instances), dictionary_(new Json::Value()) {}
91 // Can't use '= default' on the header because the compiler complains of
92 // Json::Value being an incomplete type
93 NvramConfig::~NvramConfig() = default;
94
95 NvramConfig::NvramConfig(NvramConfig&&) = default;
96 NvramConfig& NvramConfig::operator=(NvramConfig&&) = default;
97
ForInstance(int num) const98 NvramConfig::InstanceSpecific NvramConfig::ForInstance(int num) const {
99 return InstanceSpecific(this, std::to_string(num));
100 }
101
ConfigFileLocation() const102 std::string NvramConfig::ConfigFileLocation() const {
103 return cuttlefish::AbsolutePath(
104 cuttlefish::modem::DeviceConfig::PerInstancePath("modem_nvram.json"));
105 }
106
LoadFromFile(const char * file)107 bool NvramConfig::LoadFromFile(const char* file) {
108 auto real_file_path = cuttlefish::AbsolutePath(file);
109 if (real_file_path.empty()) {
110 LOG(ERROR) << "Could not get real path for file " << file;
111 return false;
112 }
113
114 Json::Reader reader;
115 std::ifstream ifs(real_file_path);
116 if (!reader.parse(ifs, *dictionary_)) {
117 LOG(ERROR) << "Could not read config file " << file << ": "
118 << reader.getFormattedErrorMessages();
119 return false;
120 }
121 return true;
122 }
123
SaveToFile(const std::string & file) const124 bool NvramConfig::SaveToFile(const std::string& file) const {
125 std::ofstream ofs(file);
126 if (!ofs.is_open()) {
127 LOG(ERROR) << "Unable to write to file " << file;
128 return false;
129 }
130 ofs << *dictionary_;
131 return !ofs.fail();
132 }
133
InitDefaultNvramConfig()134 void NvramConfig::InitDefaultNvramConfig() {
135 for (size_t num = 0; num < total_instances_; num++) {
136 auto instance = ForInstance(num);
137 instance.set_modem_technoloy(kDefaultModemTechnoloy);
138 instance.set_network_selection_mode(kDefaultNetworkSelectionMode);
139 instance.set_preferred_network_mode(kDefaultPreferredNetworkMode);
140 instance.set_emergency_mode(kDefaultEmergencyMode);
141 }
142 }
143
Dictionary() const144 const Json::Value* NvramConfig::InstanceSpecific::Dictionary() const {
145 return &(*config_->dictionary_)[kInstances][id_];
146 }
147
Dictionary()148 Json::Value* NvramConfig::InstanceSpecific::Dictionary() {
149 return &(*config_->dictionary_)[kInstances][id_];
150 }
151
network_selection_mode() const152 int NvramConfig::InstanceSpecific::network_selection_mode() const {
153 return (*Dictionary())[kNetworkSelectionMode].asInt();
154 }
155
set_network_selection_mode(int mode)156 void NvramConfig::InstanceSpecific::set_network_selection_mode(int mode) {
157 (*Dictionary())[kNetworkSelectionMode] = mode;
158 }
159
operator_numeric() const160 std::string NvramConfig::InstanceSpecific::operator_numeric() const {
161 return (*Dictionary())[kOperatorNumeric].asString();
162 }
163
set_operator_numeric(std::string & operator_numeric)164 void NvramConfig::InstanceSpecific::set_operator_numeric(std::string& operator_numeric) {
165 (*Dictionary())[kOperatorNumeric] = operator_numeric;
166 }
167
modem_technoloy() const168 int NvramConfig::InstanceSpecific::modem_technoloy() const {
169 return (*Dictionary())[kModemTechnoloy].asInt();
170 }
171
set_modem_technoloy(int technoloy)172 void NvramConfig::InstanceSpecific::set_modem_technoloy(int technoloy) {
173 (*Dictionary())[kModemTechnoloy] = technoloy;
174 }
175
preferred_network_mode() const176 int NvramConfig::InstanceSpecific::preferred_network_mode() const {
177 return (*Dictionary())[kPreferredNetworkMode].asInt();
178 }
179
set_preferred_network_mode(int mode)180 void NvramConfig::InstanceSpecific::set_preferred_network_mode(int mode) {
181 (*Dictionary())[kPreferredNetworkMode] = mode;
182 }
183
emergency_mode() const184 bool NvramConfig::InstanceSpecific::emergency_mode() const {
185 return (*Dictionary())[kEmergencyMode].asBool();
186 }
187
set_emergency_mode(bool mode)188 void NvramConfig::InstanceSpecific::set_emergency_mode(bool mode) {
189 (*Dictionary())[kEmergencyMode] = mode;
190 }
191
192 } // namespace cuttlefish
193