blob: 2278e0461189e6e65653e8ff814fb12306207195 [file] [log] [blame]
Inseob Kim5f8f32c2018-08-24 11:10:44 +09001/*
2 * Copyright (C) 2018 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 "Common.h"
18
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <unistd.h>
22
Inseob Kim14e51872018-10-25 14:27:33 +090023#include <algorithm>
Inseob Kim5f8f32c2018-08-24 11:10:44 +090024#include <cctype>
25#include <cerrno>
26#include <cmath>
27#include <cstdlib>
28#include <cstring>
29#include <initializer_list>
30#include <memory>
31#include <regex>
32#include <string>
33#include <unordered_set>
34#include <vector>
35
36#include <android-base/file.h>
Inseob Kim1ca03f32019-06-08 16:31:59 +090037#include <android-base/logging.h>
Inseob Kim5f8f32c2018-08-24 11:10:44 +090038#include <android-base/strings.h>
39#include <google/protobuf/text_format.h>
40
41#include "sysprop.pb.h"
42
Inseob Kim053b83d2019-06-26 13:41:51 +090043using android::base::Result;
44
Inseob Kim5f8f32c2018-08-24 11:10:44 +090045namespace {
46
Inseob Kim14e51872018-10-25 14:27:33 +090047std::string GenerateDefaultPropName(const sysprop::Properties& props,
48 const sysprop::Property& prop);
Inseob Kim5f8f32c2018-08-24 11:10:44 +090049bool IsCorrectIdentifier(const std::string& name);
Inseob Kim053b83d2019-06-26 13:41:51 +090050Result<void> ValidateProp(const sysprop::Properties& props,
51 const sysprop::Property& prop);
52Result<void> ValidateProps(const sysprop::Properties& props);
Inseob Kim5f8f32c2018-08-24 11:10:44 +090053
Inseob Kim14e51872018-10-25 14:27:33 +090054std::string GenerateDefaultPropName(const sysprop::Properties& props,
55 const sysprop::Property& prop) {
56 std::string ret;
57
58 if (prop.access() != sysprop::ReadWrite) ret = "ro.";
59
60 switch (props.owner()) {
61 case sysprop::Vendor:
62 ret += "vendor.";
63 break;
64 case sysprop::Odm:
65 ret += "odm.";
66 break;
67 default:
68 break;
69 }
70
71 ret += prop.api_name();
72
73 return ret;
74}
75
Inseob Kim5f8f32c2018-08-24 11:10:44 +090076bool IsCorrectIdentifier(const std::string& name) {
77 if (name.empty()) return false;
78 if (std::isalpha(name[0]) == 0 && name[0] != '_') return false;
79
Inseob Kim14e51872018-10-25 14:27:33 +090080 return std::all_of(name.begin() + 1, name.end(), [](char ch) {
81 return std::isalnum(ch) != 0 || ch == '_';
82 });
Inseob Kim5f8f32c2018-08-24 11:10:44 +090083}
84
Jiyong Park87d439d2019-11-27 19:24:07 +090085bool IsCorrectName(const std::string& name,
86 const std::unordered_set<char>& allowed_chars) {
Inseob Kim5f8f32c2018-08-24 11:10:44 +090087 if (name.empty()) return false;
Jiyong Park87d439d2019-11-27 19:24:07 +090088 if (!std::isalpha(*name.begin())) return false;
Inseob Kim5f8f32c2018-08-24 11:10:44 +090089
Jiyong Park87d439d2019-11-27 19:24:07 +090090 return std::all_of(name.begin(), name.end(), [allowed_chars](char ch) {
91 return std::isalnum(ch) != 0 || allowed_chars.count(ch) != 0;
Inseob Kim14e51872018-10-25 14:27:33 +090092 });
Inseob Kim5f8f32c2018-08-24 11:10:44 +090093}
94
Jiyong Park87d439d2019-11-27 19:24:07 +090095bool IsCorrectPropertyName(const std::string& name) {
96 std::unordered_set<char> allowed{'_', '-', '.'};
97 if (android::base::StartsWith(name, "ctl.")) {
98 allowed.emplace('$');
99 }
100 return IsCorrectName(name, allowed);
101}
102
103bool IsCorrectApiName(const std::string& name) {
104 static std::unordered_set<char> allowed{'_', '-'};
105 return IsCorrectName(name, allowed);
106}
107
Inseob Kim053b83d2019-06-26 13:41:51 +0900108Result<void> ValidateProp(const sysprop::Properties& props,
109 const sysprop::Property& prop) {
Jiyong Park87d439d2019-11-27 19:24:07 +0900110 if (!IsCorrectApiName(prop.api_name())) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900111 return Errorf("Invalid API name \"{}\"", prop.api_name());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900112 }
113
114 if (prop.type() == sysprop::Enum || prop.type() == sysprop::EnumList) {
115 std::vector<std::string> names =
116 android::base::Split(prop.enum_values(), "|");
117 if (names.empty()) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900118 return Errorf("Enum values are empty for API \"{}\"", prop.api_name());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900119 }
120
121 for (const std::string& name : names) {
122 if (!IsCorrectIdentifier(name)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900123 return Errorf("Invalid enum value \"{}\" for API \"{}\"", name,
124 prop.api_name());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900125 }
126 }
127
128 std::unordered_set<std::string> name_set;
129 for (const std::string& name : names) {
Inseob Kimf346e502019-01-04 10:32:39 +0900130 if (!name_set.insert(ToUpper(name)).second) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900131 return Errorf("Duplicated enum value \"{}\" for API \"{}\"", name,
132 prop.api_name());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900133 }
134 }
135 }
136
Inseob Kim14e51872018-10-25 14:27:33 +0900137 std::string prop_name = prop.prop_name();
138 if (prop_name.empty()) prop_name = GenerateDefaultPropName(props, prop);
139
Jiyong Park87d439d2019-11-27 19:24:07 +0900140 if (!IsCorrectPropertyName(prop_name)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900141 return Errorf("Invalid prop name \"{}\"", prop.prop_name());
Inseob Kim14e51872018-10-25 14:27:33 +0900142 }
143
Inseob Kimfcb5db72019-03-15 14:33:01 +0900144 static const std::regex vendor_regex(
145 "(init\\.svc\\.|ro\\.|persist\\.)?vendor\\..+|ro\\.hardware\\..+");
146 static const std::regex odm_regex(
147 "(init\\.svc\\.|ro\\.|persist\\.)?odm\\..+|ro\\.hardware\\..+");
Inseob Kim14e51872018-10-25 14:27:33 +0900148
149 switch (props.owner()) {
150 case sysprop::Platform:
151 if (std::regex_match(prop_name, vendor_regex) ||
152 std::regex_match(prop_name, odm_regex)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900153 return Errorf(
154 "Prop \"{}\" owned by platform cannot have vendor. or odm. "
155 "namespace",
156 prop_name);
Inseob Kim14e51872018-10-25 14:27:33 +0900157 }
158 break;
159 case sysprop::Vendor:
160 if (!std::regex_match(prop_name, vendor_regex)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900161 return Errorf(
162 "Prop \"{}\" owned by vendor should have vendor. namespace",
163 prop_name);
Inseob Kim14e51872018-10-25 14:27:33 +0900164 }
165 break;
166 case sysprop::Odm:
167 if (!std::regex_match(prop_name, odm_regex)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900168 return Errorf("Prop \"{}\" owned by odm should have odm. namespace",
169 prop_name);
Inseob Kim14e51872018-10-25 14:27:33 +0900170 }
171 break;
Inseob Kim8802c7d2018-11-02 15:01:47 +0900172 default:
173 break;
Inseob Kim14e51872018-10-25 14:27:33 +0900174 }
175
176 switch (prop.access()) {
177 case sysprop::ReadWrite:
178 if (android::base::StartsWith(prop_name, "ro.")) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900179 return Errorf("Prop \"{}\" is ReadWrite and also have prefix \"ro.\"",
180 prop_name);
Inseob Kim14e51872018-10-25 14:27:33 +0900181 }
182 break;
183 default:
Inseob Kimaa5054b2018-12-07 00:13:38 +0900184 /*
185 * TODO: Some properties don't have prefix "ro." but not written in any
186 * Java or C++ codes. They might be misnamed and should be readonly. Will
187 * uncomment this check after fixing them all / or making a whitelist for
188 * them
Inseob Kim14e51872018-10-25 14:27:33 +0900189 if (!android::base::StartsWith(prop_name, "ro.")) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900190 return Errorf("Prop \"{}\" isn't ReadWrite, but don't have prefix
191 \"ro.\"", prop_name);
Inseob Kim14e51872018-10-25 14:27:33 +0900192 }
Inseob Kimaa5054b2018-12-07 00:13:38 +0900193 */
Inseob Kim14e51872018-10-25 14:27:33 +0900194 break;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900195 }
196
Inseob Kim9c5147d2019-03-06 11:36:36 +0900197 if (prop.integer_as_bool() && !(prop.type() == sysprop::Boolean ||
198 prop.type() == sysprop::BooleanList)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900199 return Errorf("Prop \"{}\" has integer_as_bool: true, but not a boolean",
200 prop_name);
Inseob Kim9c5147d2019-03-06 11:36:36 +0900201 }
202
Inseob Kim053b83d2019-06-26 13:41:51 +0900203 return {};
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900204}
205
Inseob Kim053b83d2019-06-26 13:41:51 +0900206Result<void> ValidateProps(const sysprop::Properties& props) {
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900207 std::vector<std::string> names = android::base::Split(props.module(), ".");
208 if (names.size() <= 1) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900209 return Errorf("Invalid module name \"{}\"", props.module());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900210 }
211
212 for (const auto& name : names) {
213 if (!IsCorrectIdentifier(name)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900214 return Errorf("Invalid name \"{}\" in module", name);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900215 }
216 }
217
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900218 if (props.prop_size() == 0) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900219 return Errorf("There is no defined property");
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900220 }
221
222 for (int i = 0; i < props.prop_size(); ++i) {
223 const auto& prop = props.prop(i);
Bernie Innocenti7ac8da42020-02-06 23:30:12 +0900224 if (auto res = ValidateProp(props, prop); !res.ok()) return res;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900225 }
226
227 std::unordered_set<std::string> prop_names;
228
229 for (int i = 0; i < props.prop_size(); ++i) {
230 const auto& prop = props.prop(i);
Inseob Kim14e51872018-10-25 14:27:33 +0900231 auto res = prop_names.insert(ApiNameToIdentifier(prop.api_name()));
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900232
233 if (!res.second) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900234 return Errorf("Duplicated API name \"{}\"", prop.api_name());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900235 }
236 }
237
Inseob Kim053b83d2019-06-26 13:41:51 +0900238 return {};
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900239}
240
Inseob Kim900fbad2019-06-26 14:09:20 +0900241void SetDefaultValues(sysprop::Properties* props) {
242 for (int i = 0; i < props->prop_size(); ++i) {
243 // set each optional field to its default value
244 sysprop::Property& prop = *props->mutable_prop(i);
245 if (prop.prop_name().empty())
246 prop.set_prop_name(GenerateDefaultPropName(*props, prop));
247 if (prop.scope() == sysprop::Scope::System) {
248 LOG(WARNING) << "Sysprop API " << prop.api_name()
249 << ": System scope is deprecated."
250 << " Please use Public scope instead.";
251 prop.set_scope(sysprop::Scope::Public);
252 }
253 }
254}
255
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900256} // namespace
257
Inseob Kimb04d6192018-12-14 08:33:16 +0900258bool IsListProp(const sysprop::Property& prop) {
259 switch (prop.type()) {
260 case sysprop::BooleanList:
261 case sysprop::IntegerList:
262 case sysprop::LongList:
263 case sysprop::DoubleList:
264 case sysprop::StringList:
265 case sysprop::EnumList:
266 return true;
267 default:
268 return false;
269 }
270}
271
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900272std::string GetModuleName(const sysprop::Properties& props) {
273 const std::string& module = props.module();
274 return module.substr(module.rfind('.') + 1);
275}
276
Inseob Kim053b83d2019-06-26 13:41:51 +0900277Result<sysprop::Properties> ParseProps(const std::string& input_file_path) {
278 sysprop::Properties ret;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900279 std::string file_contents;
280
281 if (!android::base::ReadFileToString(input_file_path, &file_contents, true)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900282 return ErrnoErrorf("Error reading file {}", input_file_path);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900283 }
284
Inseob Kim053b83d2019-06-26 13:41:51 +0900285 if (!google::protobuf::TextFormat::ParseFromString(file_contents, &ret)) {
286 return Errorf("Error parsing file {}", input_file_path);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900287 }
288
Bernie Innocenti7ac8da42020-02-06 23:30:12 +0900289 if (auto res = ValidateProps(ret); !res.ok()) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900290 return res.error();
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900291 }
292
Inseob Kim900fbad2019-06-26 14:09:20 +0900293 SetDefaultValues(&ret);
294
295 return ret;
296}
297
298Result<sysprop::SyspropLibraryApis> ParseApiFile(
299 const std::string& input_file_path) {
300 sysprop::SyspropLibraryApis ret;
301 std::string file_contents;
302
303 if (!android::base::ReadFileToString(input_file_path, &file_contents, true)) {
304 return ErrnoErrorf("Error reading file {}", input_file_path);
305 }
306
307 if (!google::protobuf::TextFormat::ParseFromString(file_contents, &ret)) {
308 return Errorf("Error parsing file {}", input_file_path);
309 }
310
311 std::unordered_set<std::string> modules;
312
313 for (int i = 0; i < ret.props_size(); ++i) {
314 sysprop::Properties* props = ret.mutable_props(i);
315
316 if (!modules.insert(props->module()).second) {
317 return Errorf("Error parsing file {}: duplicated module {}",
318 input_file_path, props->module());
Inseob Kim1ca03f32019-06-08 16:31:59 +0900319 }
Inseob Kim900fbad2019-06-26 14:09:20 +0900320
Bernie Innocenti7ac8da42020-02-06 23:30:12 +0900321 if (auto res = ValidateProps(*props); !res.ok()) {
Inseob Kim900fbad2019-06-26 14:09:20 +0900322 return res.error();
323 }
324
325 SetDefaultValues(props);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900326 }
327
Inseob Kim053b83d2019-06-26 13:41:51 +0900328 return ret;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900329}
330
Inseob Kimf346e502019-01-04 10:32:39 +0900331std::string ToUpper(std::string str) {
332 for (char& ch : str) {
333 ch = toupper(ch);
334 }
335 return str;
336}
337
Inseob Kim14e51872018-10-25 14:27:33 +0900338std::string ApiNameToIdentifier(const std::string& name) {
339 static const std::regex kRegexAllowed{"-|\\."};
340 return (isdigit(name[0]) ? "_" : "") +
341 std::regex_replace(name, kRegexAllowed, "_");
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900342}