1 /*
2 * Copyright (C) 2019 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 "ApiChecker.h"
18
19 #include <string>
20 #include <unordered_map>
21
22 using android::base::Result;
23
24 namespace {
25
CompareProps(const sysprop::Properties & latest,const sysprop::Properties & current)26 Result<void> CompareProps(const sysprop::Properties& latest,
27 const sysprop::Properties& current) {
28 std::unordered_map<std::string, sysprop::Property> props;
29 std::unordered_map<std::string, sysprop::Property> legacy_props;
30
31 for (int i = 0; i < current.prop_size(); ++i) {
32 const auto& prop = current.prop(i);
33 props[prop.api_name()] = prop;
34 if (!prop.legacy_prop_name().empty()) {
35 legacy_props[prop.legacy_prop_name()] = prop;
36 }
37 }
38
39 std::string err;
40
41 bool latest_empty = true;
42 for (int i = 0; i < latest.prop_size(); ++i) {
43 const auto& latest_prop = latest.prop(i);
44 if (latest_prop.deprecated() || latest_prop.scope() == sysprop::Internal) {
45 continue;
46 }
47
48 latest_empty = false;
49
50 // Error if a prop from the latest API doesn't exist in the current API.
51 // But allow removal if any legacy_prop_name in the current API is
52 // identical to prop_name.
53 bool legacy = false;
54 auto itr = props.find(latest_prop.api_name());
55 sysprop::Property current_prop;
56 if (itr != props.end()) {
57 current_prop = itr->second;
58 } else {
59 auto legacy_itr = legacy_props.find(latest_prop.prop_name());
60 if (legacy_itr != legacy_props.end()) {
61 legacy = true;
62 current_prop = legacy_itr->second;
63 } else {
64 err += "Prop " + latest_prop.api_name() + " has been removed\n";
65 continue;
66 }
67 }
68
69 if (latest_prop.type() != current_prop.type()) {
70 err += "Type of prop " + latest_prop.api_name() + " has been changed\n";
71 }
72 // Readonly > Writeonce > ReadWrite
73 if (latest_prop.access() > current_prop.access()) {
74 err += "Accessibility of prop " + latest_prop.api_name() +
75 " has become more restrictive\n";
76 }
77 // Public < Internal
78 if (latest_prop.scope() < current_prop.scope()) {
79 err += "Scope of prop " + latest_prop.api_name() +
80 " has become more restrictive\n";
81 }
82 if (latest_prop.enum_values() != current_prop.enum_values()) {
83 err += "Enum values of prop " + latest_prop.api_name() +
84 " has been changed\n";
85 }
86 if (latest_prop.integer_as_bool() != current_prop.integer_as_bool()) {
87 err += "Integer-as-bool of prop " + latest_prop.api_name() +
88 " has been changed\n";
89 }
90 // If current_prop is new and latest_prop is legacy, skip prop name compare
91 // because latest_prop.prop_name() == current_prop.legacy_prop_name()
92 if (!legacy) {
93 if (latest_prop.prop_name() != current_prop.prop_name()) {
94 err += "Underlying property of prop " + latest_prop.api_name() +
95 " has been changed\n";
96 }
97 if (latest_prop.legacy_prop_name() != current_prop.legacy_prop_name()) {
98 err += "Legacy prop of prop " + latest_prop.api_name() +
99 " has been changed\n";
100 }
101 }
102 }
103
104 if (!latest_empty) {
105 if (latest.owner() != current.owner()) {
106 err += "owner of module " + latest.module() + " has been changed\n";
107 }
108 }
109
110 if (err.empty())
111 return {};
112 else
113 return Errorf("{}", err);
114 }
115
116 } // namespace
117
CompareApis(const sysprop::SyspropLibraryApis & latest,const sysprop::SyspropLibraryApis & current)118 Result<void> CompareApis(const sysprop::SyspropLibraryApis& latest,
119 const sysprop::SyspropLibraryApis& current) {
120 std::unordered_map<std::string, sysprop::Properties> propsMap;
121
122 for (int i = 0; i < current.props_size(); ++i) {
123 propsMap[current.props(i).module()] = current.props(i);
124 }
125
126 for (int i = 0; i < latest.props_size(); ++i) {
127 // Checking whether propsMap contains latest.props(i)->module() or not
128 // is intentionally skipped to handle the case that latest.props(i) has
129 // only deprecated properties.
130 if (auto res =
131 CompareProps(latest.props(i), propsMap[latest.props(i).module()]);
132 !res.ok()) {
133 return res;
134 }
135 }
136
137 return {};
138 }
139