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
24 #include "common/libs/utils/files.h"
25 #include "host/commands/modem_simulator/device_config.h"
26
27 namespace cuttlefish {
28
29 static constexpr char kInstances[] = "instances";
30 static constexpr char kNetworkSelectionMode[] = "network_selection_mode";
31 static constexpr char kOperatorNumeric[] = "operator_numeric";
32 static constexpr char kModemTechnoloy[] = "modem_technoloy";
33 static constexpr char kPreferredNetworkMode[] = "preferred_network_mode";
34 static constexpr char kEmergencyMode[] = "emergency_mode";
35
36 static constexpr int kDefaultNetworkSelectionMode = 0; // AUTOMATIC
37 static constexpr int kDefaultModemTechnoloy = 0x10; // LTE
38 static constexpr int kDefaultPreferredNetworkMode = 0x13; // LTE | WCDMA | GSM
39 static constexpr bool kDefaultEmergencyMode = false;
40
41 /**
42 * Creates the (initially empty) config object and populates it with values from
43 * the config file "modem_nvram.json" located in the cuttlefish instance path,
44 * or uses the default value if the config file not exists,
45 * Returns nullptr if there was an error loading from file
46 */
BuildConfigImpl(size_t num_instances,int sim_type)47 NvramConfig* NvramConfig::BuildConfigImpl(size_t num_instances, int sim_type) {
48 auto ret = new NvramConfig(num_instances, sim_type);
49 if (ret) {
50 const auto nvram_config_path = ConfigFileLocation();
51 if (!cuttlefish::FileExists(nvram_config_path) ||
52 !cuttlefish::FileHasContent(nvram_config_path.c_str())) {
53 ret->InitDefaultNvramConfig();
54 } else {
55 auto loaded = ret->LoadFromFile(nvram_config_path.c_str());
56 if (!loaded) {
57 /** Bug: (b/315167296)
58 * Fall back to default nvram config if LoadFromFile fails.
59 */
60 ret->InitDefaultNvramConfig();
61 }
62 }
63 }
64 return ret;
65 }
66
67 std::unique_ptr<NvramConfig> NvramConfig::s_nvram_config;
68
InitNvramConfigService(size_t num_instances,int sim_type)69 void NvramConfig::InitNvramConfigService(size_t num_instances, int sim_type) {
70 static std::once_flag once_flag;
71
72 std::call_once(once_flag, [num_instances, sim_type]() {
73 NvramConfig::s_nvram_config.reset(BuildConfigImpl(num_instances, sim_type));
74 });
75 }
76
Get()77 /* static */ const NvramConfig* NvramConfig::Get() {
78 return s_nvram_config.get();
79 }
80
SaveToFile()81 void NvramConfig::SaveToFile() {
82 auto nvram_config = Get();
83 const auto nvram_config_file = ConfigFileLocation();
84 nvram_config->SaveToFile(nvram_config_file);
85 }
86
NvramConfig(size_t num_instances,int sim_type)87 NvramConfig::NvramConfig(size_t num_instances, int sim_type)
88 : total_instances_(num_instances),
89 sim_type_(sim_type),
90 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()102 /* static */ std::string NvramConfig::ConfigFileLocation() {
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::CharReaderBuilder builder;
115 std::ifstream ifs = modem::DeviceConfig::open_ifstream_crossplat(real_file_path.c_str());
116 std::string errorMessage;
117 if (!Json::parseFromStream(builder, ifs, dictionary_.get(), &errorMessage)) {
118 LOG(ERROR) << "Could not read config file " << file << ": "
119 << errorMessage;
120 return false;
121 }
122 return true;
123 }
124
SaveToFile(const std::string & file) const125 bool NvramConfig::SaveToFile(const std::string& file) const {
126 std::ofstream ofs = modem::DeviceConfig::open_ofstream_crossplat(file.c_str());
127 if (!ofs.is_open()) {
128 LOG(ERROR) << "Unable to write to file " << file;
129 return false;
130 }
131 ofs << *dictionary_;
132 return !ofs.fail();
133 }
134
InitDefaultNvramConfig()135 void NvramConfig::InitDefaultNvramConfig() {
136 for (size_t num = 0; num < total_instances_; num++) {
137 auto instance = ForInstance(num);
138 instance.set_modem_technoloy(kDefaultModemTechnoloy);
139 instance.set_network_selection_mode(kDefaultNetworkSelectionMode);
140 instance.set_preferred_network_mode(kDefaultPreferredNetworkMode);
141 instance.set_emergency_mode(kDefaultEmergencyMode);
142 }
143 }
144
Dictionary() const145 const Json::Value* NvramConfig::InstanceSpecific::Dictionary() const {
146 return &(*config_->dictionary_)[kInstances][id_];
147 }
148
Dictionary()149 Json::Value* NvramConfig::InstanceSpecific::Dictionary() {
150 return &(*config_->dictionary_)[kInstances][id_];
151 }
152
network_selection_mode() const153 int NvramConfig::InstanceSpecific::network_selection_mode() const {
154 return (*Dictionary())[kNetworkSelectionMode].asInt();
155 }
156
set_network_selection_mode(int mode)157 void NvramConfig::InstanceSpecific::set_network_selection_mode(int mode) {
158 (*Dictionary())[kNetworkSelectionMode] = mode;
159 }
160
operator_numeric() const161 std::string NvramConfig::InstanceSpecific::operator_numeric() const {
162 return (*Dictionary())[kOperatorNumeric].asString();
163 }
164
set_operator_numeric(std::string & operator_numeric)165 void NvramConfig::InstanceSpecific::set_operator_numeric(std::string& operator_numeric) {
166 (*Dictionary())[kOperatorNumeric] = operator_numeric;
167 }
168
modem_technoloy() const169 int NvramConfig::InstanceSpecific::modem_technoloy() const {
170 return (*Dictionary())[kModemTechnoloy].asInt();
171 }
172
set_modem_technoloy(int technoloy)173 void NvramConfig::InstanceSpecific::set_modem_technoloy(int technoloy) {
174 (*Dictionary())[kModemTechnoloy] = technoloy;
175 }
176
preferred_network_mode() const177 int NvramConfig::InstanceSpecific::preferred_network_mode() const {
178 return (*Dictionary())[kPreferredNetworkMode].asInt();
179 }
180
set_preferred_network_mode(int mode)181 void NvramConfig::InstanceSpecific::set_preferred_network_mode(int mode) {
182 (*Dictionary())[kPreferredNetworkMode] = mode;
183 }
184
emergency_mode() const185 bool NvramConfig::InstanceSpecific::emergency_mode() const {
186 return (*Dictionary())[kEmergencyMode].asBool();
187 }
188
set_emergency_mode(bool mode)189 void NvramConfig::InstanceSpecific::set_emergency_mode(bool mode) {
190 (*Dictionary())[kEmergencyMode] = mode;
191 }
192
sim_type() const193 int NvramConfig::sim_type() const {
194 return sim_type_;
195 }
196
197 } // namespace cuttlefish
198