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 const char* kSimType = "sim_type";
37
38 const int kDefaultNetworkSelectionMode = 0; // AUTOMATIC
39 const std::string kDefaultOperatorNumeric = "";
40 const int kDefaultModemTechnoloy = 0x10; // LTE
41 const int kDefaultPreferredNetworkMode = 0x13; // LTE | WCDMA | GSM
42 const bool kDefaultEmergencyMode = false;
43
44 /**
45 * Creates the (initially empty) config object and populates it with values from
46 * the config file "modem_nvram.json" located in the cuttlefish instance path,
47 * or uses the default value if the config file not exists,
48 * Returns nullptr if there was an error loading from file
49 */
BuildConfigImpl(size_t num_instances,int sim_type)50 NvramConfig* NvramConfig::BuildConfigImpl(size_t num_instances, int sim_type) {
51 auto nvram_config_path =
52 cuttlefish::modem::DeviceConfig::PerInstancePath("modem_nvram.json");
53
54 auto ret = new NvramConfig(num_instances, sim_type);
55 if (ret) {
56 if (!cuttlefish::FileExists(nvram_config_path) ||
57 !cuttlefish::FileHasContent(nvram_config_path.c_str())) {
58 ret->InitDefaultNvramConfig();
59 } else {
60 auto loaded = ret->LoadFromFile(nvram_config_path.c_str());
61 if (!loaded) {
62 delete ret;
63 return nullptr;
64 }
65 }
66 }
67 return ret;
68 }
69
70 std::unique_ptr<NvramConfig> NvramConfig::s_nvram_config;
71
InitNvramConfigService(size_t num_instances,int sim_type)72 void NvramConfig::InitNvramConfigService(size_t num_instances, int sim_type) {
73 static std::once_flag once_flag;
74
75 std::call_once(once_flag, [num_instances, sim_type]() {
76 NvramConfig::s_nvram_config.reset(BuildConfigImpl(num_instances, sim_type));
77 });
78 }
79
Get()80 /* static */ const NvramConfig* NvramConfig::Get() {
81 return s_nvram_config.get();
82 }
83
SaveToFile()84 void NvramConfig::SaveToFile() {
85 auto nvram_config = Get();
86 auto nvram_config_file = nvram_config->ConfigFileLocation();
87 nvram_config->SaveToFile(nvram_config_file);
88 }
89
NvramConfig(size_t num_instances,int sim_type)90 NvramConfig::NvramConfig(size_t num_instances, int sim_type)
91 : total_instances_(num_instances),
92 sim_type_(sim_type),
93 dictionary_(new Json::Value()) {}
94 // Can't use '= default' on the header because the compiler complains of
95 // Json::Value being an incomplete type
96 NvramConfig::~NvramConfig() = default;
97
98 NvramConfig::NvramConfig(NvramConfig&&) = default;
99 NvramConfig& NvramConfig::operator=(NvramConfig&&) = default;
100
ForInstance(int num) const101 NvramConfig::InstanceSpecific NvramConfig::ForInstance(int num) const {
102 return InstanceSpecific(this, std::to_string(num));
103 }
104
ConfigFileLocation() const105 std::string NvramConfig::ConfigFileLocation() const {
106 return cuttlefish::AbsolutePath(
107 cuttlefish::modem::DeviceConfig::PerInstancePath("modem_nvram.json"));
108 }
109
LoadFromFile(const char * file)110 bool NvramConfig::LoadFromFile(const char* file) {
111 auto real_file_path = cuttlefish::AbsolutePath(file);
112 if (real_file_path.empty()) {
113 LOG(ERROR) << "Could not get real path for file " << file;
114 return false;
115 }
116
117 Json::CharReaderBuilder builder;
118 std::ifstream ifs = modem::DeviceConfig::open_ifstream_crossplat(real_file_path.c_str());
119 std::string errorMessage;
120 if (!Json::parseFromStream(builder, ifs, dictionary_.get(), &errorMessage)) {
121 LOG(ERROR) << "Could not read config file " << file << ": "
122 << errorMessage;
123 return false;
124 }
125 return true;
126 }
127
SaveToFile(const std::string & file) const128 bool NvramConfig::SaveToFile(const std::string& file) const {
129 std::ofstream ofs = modem::DeviceConfig::open_ofstream_crossplat(file.c_str());
130 if (!ofs.is_open()) {
131 LOG(ERROR) << "Unable to write to file " << file;
132 return false;
133 }
134 ofs << *dictionary_;
135 return !ofs.fail();
136 }
137
InitDefaultNvramConfig()138 void NvramConfig::InitDefaultNvramConfig() {
139 for (size_t num = 0; num < total_instances_; num++) {
140 auto instance = ForInstance(num);
141 instance.set_modem_technoloy(kDefaultModemTechnoloy);
142 instance.set_network_selection_mode(kDefaultNetworkSelectionMode);
143 instance.set_preferred_network_mode(kDefaultPreferredNetworkMode);
144 instance.set_emergency_mode(kDefaultEmergencyMode);
145 }
146 }
147
Dictionary() const148 const Json::Value* NvramConfig::InstanceSpecific::Dictionary() const {
149 return &(*config_->dictionary_)[kInstances][id_];
150 }
151
Dictionary()152 Json::Value* NvramConfig::InstanceSpecific::Dictionary() {
153 return &(*config_->dictionary_)[kInstances][id_];
154 }
155
network_selection_mode() const156 int NvramConfig::InstanceSpecific::network_selection_mode() const {
157 return (*Dictionary())[kNetworkSelectionMode].asInt();
158 }
159
set_network_selection_mode(int mode)160 void NvramConfig::InstanceSpecific::set_network_selection_mode(int mode) {
161 (*Dictionary())[kNetworkSelectionMode] = mode;
162 }
163
operator_numeric() const164 std::string NvramConfig::InstanceSpecific::operator_numeric() const {
165 return (*Dictionary())[kOperatorNumeric].asString();
166 }
167
set_operator_numeric(std::string & operator_numeric)168 void NvramConfig::InstanceSpecific::set_operator_numeric(std::string& operator_numeric) {
169 (*Dictionary())[kOperatorNumeric] = operator_numeric;
170 }
171
modem_technoloy() const172 int NvramConfig::InstanceSpecific::modem_technoloy() const {
173 return (*Dictionary())[kModemTechnoloy].asInt();
174 }
175
set_modem_technoloy(int technoloy)176 void NvramConfig::InstanceSpecific::set_modem_technoloy(int technoloy) {
177 (*Dictionary())[kModemTechnoloy] = technoloy;
178 }
179
preferred_network_mode() const180 int NvramConfig::InstanceSpecific::preferred_network_mode() const {
181 return (*Dictionary())[kPreferredNetworkMode].asInt();
182 }
183
set_preferred_network_mode(int mode)184 void NvramConfig::InstanceSpecific::set_preferred_network_mode(int mode) {
185 (*Dictionary())[kPreferredNetworkMode] = mode;
186 }
187
emergency_mode() const188 bool NvramConfig::InstanceSpecific::emergency_mode() const {
189 return (*Dictionary())[kEmergencyMode].asBool();
190 }
191
set_emergency_mode(bool mode)192 void NvramConfig::InstanceSpecific::set_emergency_mode(bool mode) {
193 (*Dictionary())[kEmergencyMode] = mode;
194 }
195
sim_type() const196 int NvramConfig::sim_type() const {
197 return sim_type_;
198 }
199
200 } // namespace cuttlefish
201