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