You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.5 KiB
139 lines
4.5 KiB
/*
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "ApiChecker.h"
|
|
|
|
#include <string>
|
|
#include <unordered_map>
|
|
|
|
using android::base::Result;
|
|
|
|
namespace {
|
|
|
|
Result<void> CompareProps(const sysprop::Properties& latest,
|
|
const sysprop::Properties& current) {
|
|
std::unordered_map<std::string, sysprop::Property> props;
|
|
std::unordered_map<std::string, sysprop::Property> legacy_props;
|
|
|
|
for (int i = 0; i < current.prop_size(); ++i) {
|
|
const auto& prop = current.prop(i);
|
|
props[prop.api_name()] = prop;
|
|
if (!prop.legacy_prop_name().empty()) {
|
|
legacy_props[prop.legacy_prop_name()] = prop;
|
|
}
|
|
}
|
|
|
|
std::string err;
|
|
|
|
bool latest_empty = true;
|
|
for (int i = 0; i < latest.prop_size(); ++i) {
|
|
const auto& latest_prop = latest.prop(i);
|
|
if (latest_prop.deprecated() || latest_prop.scope() == sysprop::Internal) {
|
|
continue;
|
|
}
|
|
|
|
latest_empty = false;
|
|
|
|
// Error if a prop from the latest API doesn't exist in the current API.
|
|
// But allow removal if any legacy_prop_name in the current API is
|
|
// identical to prop_name.
|
|
bool legacy = false;
|
|
auto itr = props.find(latest_prop.api_name());
|
|
sysprop::Property current_prop;
|
|
if (itr != props.end()) {
|
|
current_prop = itr->second;
|
|
} else {
|
|
auto legacy_itr = legacy_props.find(latest_prop.prop_name());
|
|
if (legacy_itr != legacy_props.end()) {
|
|
legacy = true;
|
|
current_prop = legacy_itr->second;
|
|
} else {
|
|
err += "Prop " + latest_prop.api_name() + " has been removed\n";
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (latest_prop.type() != current_prop.type()) {
|
|
err += "Type of prop " + latest_prop.api_name() + " has been changed\n";
|
|
}
|
|
// Readonly > Writeonce > ReadWrite
|
|
if (latest_prop.access() > current_prop.access()) {
|
|
err += "Accessibility of prop " + latest_prop.api_name() +
|
|
" has become more restrictive\n";
|
|
}
|
|
// Public < Internal
|
|
if (latest_prop.scope() < current_prop.scope()) {
|
|
err += "Scope of prop " + latest_prop.api_name() +
|
|
" has become more restrictive\n";
|
|
}
|
|
if (latest_prop.enum_values() != current_prop.enum_values()) {
|
|
err += "Enum values of prop " + latest_prop.api_name() +
|
|
" has been changed\n";
|
|
}
|
|
if (latest_prop.integer_as_bool() != current_prop.integer_as_bool()) {
|
|
err += "Integer-as-bool of prop " + latest_prop.api_name() +
|
|
" has been changed\n";
|
|
}
|
|
// If current_prop is new and latest_prop is legacy, skip prop name compare
|
|
// because latest_prop.prop_name() == current_prop.legacy_prop_name()
|
|
if (!legacy) {
|
|
if (latest_prop.prop_name() != current_prop.prop_name()) {
|
|
err += "Underlying property of prop " + latest_prop.api_name() +
|
|
" has been changed\n";
|
|
}
|
|
if (latest_prop.legacy_prop_name() != current_prop.legacy_prop_name()) {
|
|
err += "Legacy prop of prop " + latest_prop.api_name() +
|
|
" has been changed\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!latest_empty) {
|
|
if (latest.owner() != current.owner()) {
|
|
err += "owner of module " + latest.module() + " has been changed\n";
|
|
}
|
|
}
|
|
|
|
if (err.empty())
|
|
return {};
|
|
else
|
|
return Errorf("{}", err);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Result<void> CompareApis(const sysprop::SyspropLibraryApis& latest,
|
|
const sysprop::SyspropLibraryApis& current) {
|
|
std::unordered_map<std::string, sysprop::Properties> propsMap;
|
|
|
|
for (int i = 0; i < current.props_size(); ++i) {
|
|
propsMap[current.props(i).module()] = current.props(i);
|
|
}
|
|
|
|
for (int i = 0; i < latest.props_size(); ++i) {
|
|
// Checking whether propsMap contains latest.props(i)->module() or not
|
|
// is intentionally skipped to handle the case that latest.props(i) has
|
|
// only deprecated properties.
|
|
if (auto res =
|
|
CompareProps(latest.props(i), propsMap[latest.props(i).module()]);
|
|
!res.ok()) {
|
|
return res;
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|