• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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