Check the availability of types against SDK version
List<interface>, interface[]: at least Tiramisu in Java
ParcelableHolder: at least 31
Build system uses "current" as default min_sdk_version for
aidl_interface modules.
Bug: 205070744
Test: aidl_unittests
Test: aidl_integration_test
Change-Id: I8f7e86c4f87a8fd64b6f5b995000b3e32d7328b0
diff --git a/Android.bp b/Android.bp
index 0994f44..2cc0aa1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -89,6 +89,7 @@
"aidl_typenames.cpp",
"aidl.cpp",
"ast_java.cpp",
+ "check_valid.cpp",
"code_writer.cpp",
"comments.cpp",
"diagnostics.cpp",
diff --git a/aidl.cpp b/aidl.cpp
index 90b593a..568ccb8 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -40,6 +40,7 @@
#include "aidl_dumpapi.h"
#include "aidl_language.h"
#include "aidl_typenames.h"
+#include "check_valid.h"
#include "generate_aidl_mappings.h"
#include "generate_cpp.h"
#include "generate_java.h"
@@ -596,6 +597,10 @@
VisitTopDown([](const AidlNode& n) { n.MarkVisited(); }, *doc);
}
+ if (!CheckValid(*document, options)) {
+ return AidlError::BAD_TYPE;
+ }
+
if (!ValidateAnnotationContext(*document)) {
return AidlError::BAD_TYPE;
}
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index d4c5321..fd912c0 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -95,6 +95,7 @@
io_delegate_.SetFileContents(path, contents);
vector<string> args;
args.emplace_back("aidl");
+ args.emplace_back("--min_sdk_version=current");
args.emplace_back("--lang=" + to_string(lang));
for (const string& s : additional_arguments) {
args.emplace_back(s);
@@ -2087,6 +2088,7 @@
EXPECT_NE(nullptr, Parse("a/Data.aidl", extendable_parcelable, typenames_, GetLanguage()));
EXPECT_EQ("", GetCapturedStderr());
}
+
TEST_P(AidlTest, ParcelableHolderAsReturnType) {
CaptureStderr();
string parcelableholder_return_interface =
@@ -4855,6 +4857,26 @@
EXPECT_THAT(GetCapturedStderr(), HasSubstr("'void' is an invalid type for the parameter 'n'"));
}
+TEST_F(AidlTest, InterfaceVectorIsAvailableAfterTiramisu) {
+ io_delegate_.SetFileContents("p/IFoo.aidl",
+ "interface IFoo{\n"
+ " void foo(in IFoo[] n);\n"
+ " void bar(in List<IFoo> n);\n"
+ "}");
+ CaptureStderr();
+ EXPECT_FALSE(compile_aidl(
+ Options::From("aidl --lang=java --min_sdk_version 30 -o out p/IFoo.aidl"), io_delegate_));
+ auto captured_stderr = GetCapturedStderr();
+ EXPECT_THAT(captured_stderr, HasSubstr("Array of interfaces is available since"));
+ EXPECT_THAT(captured_stderr, HasSubstr("List of interfaces is available since"));
+
+ CaptureStderr();
+ EXPECT_TRUE(
+ compile_aidl(Options::From("aidl --lang=java --min_sdk_version Tiramisu -o out p/IFoo.aidl"),
+ io_delegate_));
+ EXPECT_EQ(GetCapturedStderr(), "");
+}
+
struct TypeParam {
string kind;
string literal;
@@ -5023,8 +5045,8 @@
}
io.SetFileContents("a/Target.aidl", "package a; parcelable Target { " + decl + " f; }");
- const auto options =
- Options::From(fmt::format("aidl -I . --lang={} a/Target.aidl -o out -h out", lang));
+ const auto options = Options::From(fmt::format(
+ "aidl -I . --min_sdk_version current --lang={} a/Target.aidl -o out -h out", lang));
CaptureStderr();
compile_aidl(options, io);
auto it = expectations.find(lang + "_" + kind);
diff --git a/build/aidl_gen_rule.go b/build/aidl_gen_rule.go
index f843e09..6d71d9b 100644
--- a/build/aidl_gen_rule.go
+++ b/build/aidl_gen_rule.go
@@ -192,10 +192,8 @@
if g.properties.Platform_apis {
optionalFlags = append(optionalFlags, "--min_sdk_version platform_apis")
} else {
- minSdkVer := g.properties.Min_sdk_version
- if minSdkVer != nil {
- optionalFlags = append(optionalFlags, "--min_sdk_version "+*minSdkVer)
- }
+ minSdkVer := proptools.StringDefault(g.properties.Min_sdk_version, "current")
+ optionalFlags = append(optionalFlags, "--min_sdk_version "+minSdkVer)
}
optionalFlags = append(optionalFlags, wrap("-p", g.deps.preprocessed.Strings(), "")...)
diff --git a/build/aidl_interface_backends.go b/build/aidl_interface_backends.go
index b6f47ea..6917814 100644
--- a/build/aidl_interface_backends.go
+++ b/build/aidl_interface_backends.go
@@ -212,12 +212,16 @@
// Don't create a library for the yet-to-be-frozen version.
return ""
}
-
+ minSdkVersion := i.minSdkVersion(langJava)
sdkVersion := i.properties.Backend.Java.Sdk_version
if !proptools.Bool(i.properties.Backend.Java.Platform_apis) && sdkVersion == nil {
// platform apis requires no default
sdkVersion = proptools.StringPtr("system_current")
}
+ // use sdkVersion if minSdkVersion is not set
+ if sdkVersion != nil && minSdkVersion == nil {
+ minSdkVersion = proptools.StringPtr(android.SdkSpecFrom(mctx, *sdkVersion).ApiLevel.String())
+ }
mctx.CreateModule(aidlGenFactory, &nameProperties{
Name: proptools.StringPtr(javaSourceGen),
@@ -226,7 +230,7 @@
AidlRoot: aidlRoot,
ImportsWithoutVersion: i.properties.ImportsWithoutVersion,
Stability: i.properties.Stability,
- Min_sdk_version: i.minSdkVersion(langJava),
+ Min_sdk_version: minSdkVersion,
Platform_apis: proptools.Bool(i.properties.Backend.Java.Platform_apis),
Lang: langJava,
BaseName: i.ModuleBase.Name(),
diff --git a/build/aidl_test.go b/build/aidl_test.go
index 9db4b3e..280c7c8 100644
--- a/build/aidl_test.go
+++ b/build/aidl_test.go
@@ -1379,6 +1379,22 @@
}
}
+func TestAidlModuleJavaSdkVersionDeterminesMinSdkVersion(t *testing.T) {
+ ctx, _ := testAidl(t, `
+ aidl_interface {
+ name: "myiface",
+ srcs: ["a/Foo.aidl"],
+ backend: {
+ java: {
+ sdk_version: "28",
+ },
+ },
+ }
+ `, java.FixtureWithPrebuiltApis(map[string][]string{"28": {"foo"}}))
+ params := ctx.ModuleForTests("myiface-V1-java-source", "").Output("a/Foo.java")
+ assertContains(t, params.Args["optionalFlags"], "--min_sdk_version 28")
+}
+
func TestAidlModuleNameContainsVersion(t *testing.T) {
testAidlError(t, "aidl_interface should not have '-V<number> suffix", `
aidl_interface {
diff --git a/check_valid.cpp b/check_valid.cpp
new file mode 100644
index 0000000..e7bcb8d
--- /dev/null
+++ b/check_valid.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021, 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 "check_valid.h"
+#include "aidl.h"
+
+#include <vector>
+
+namespace android {
+namespace aidl {
+
+using TypePredicate = std::function<bool(const AidlTypeSpecifier&)>;
+
+namespace {
+bool IsListOf(const AidlTypeSpecifier& type, TypePredicate pred) {
+ return type.GetName() == "List" && type.IsGeneric() && type.GetTypeParameters().size() == 1 &&
+ pred(*type.GetTypeParameters().at(0));
+}
+bool IsArrayOf(const AidlTypeSpecifier& type, TypePredicate pred) {
+ return type.IsArray() && pred(type);
+}
+bool IsInterface(const AidlTypeSpecifier& type) {
+ return type.GetDefinedType() && type.GetDefinedType()->AsInterface();
+}
+} // namespace
+
+struct CheckTypeVisitor : AidlVisitor {
+ bool success = true;
+ std::vector<TypePredicate> checkers;
+
+ void Visit(const AidlTypeSpecifier& type) override {
+ for (auto& checker : checkers) {
+ if (!checker(type)) {
+ success = false;
+ }
+ }
+ }
+
+ void Check(TypePredicate checker) { checkers.push_back(std::move(checker)); }
+};
+
+bool CheckValid(const AidlDocument& doc, const Options& options) {
+ const auto lang = options.TargetLanguage();
+ const auto min_sdk_version = options.GetMinSdkVersion();
+
+ CheckTypeVisitor v;
+
+ v.Check([&](const AidlTypeSpecifier& type) {
+ const auto valid_version = MinSdkVersionFromString("Tiramisu").value();
+ if ((IsListOf(type, IsInterface) || IsArrayOf(type, IsInterface)) &&
+ lang == Options::Language::JAVA && min_sdk_version < valid_version) {
+ const auto kind = IsListOf(type, IsInterface) ? "List" : "Array";
+ AIDL_ERROR(type) << kind << " of interfaces is available since SDK = " << valid_version
+ << " in Java. Current min_sdk_version is " << min_sdk_version << ".";
+ return false;
+ }
+ return true;
+ });
+
+ v.Check([&](const AidlTypeSpecifier& type) {
+ const auto valid_version = MinSdkVersionFromString("S").value();
+ if (type.GetName() == "ParcelableHolder" && min_sdk_version < valid_version) {
+ AIDL_ERROR(type) << " ParcelableHolder is available since SDK = " << valid_version
+ << ". Current min_sdk_version is " << min_sdk_version << ".";
+ return false;
+ }
+ return true;
+ });
+
+ VisitTopDown(v, doc);
+ return v.success;
+}
+
+} // namespace aidl
+} // namespace android
diff --git a/check_valid.h b/check_valid.h
new file mode 100644
index 0000000..0fdd220
--- /dev/null
+++ b/check_valid.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021, 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.
+ */
+
+#pragma once
+
+#include "aidl_language.h"
+#include "options.h"
+
+namespace android {
+namespace aidl {
+
+bool CheckValid(const AidlDocument& doc, const Options& options);
+
+}
+} // namespace android
\ No newline at end of file
diff --git a/options.cpp b/options.cpp
index 13fad03..3148a64 100644
--- a/options.cpp
+++ b/options.cpp
@@ -202,7 +202,7 @@
{"platform_apis", 10001},
};
-static Result<uint32_t> MinSdkVersionFromString(const std::string& str) {
+Result<uint32_t> MinSdkVersionFromString(const std::string& str) {
uint32_t num;
if (!android::base::ParseUint(str, &num, 10000u /* max */)) {
if (auto found = codeNameToVersion.find(str); found != codeNameToVersion.end()) {
@@ -586,6 +586,14 @@
return;
}
}
+ if (task_ != Options::Task::COMPILE) {
+ if (min_sdk_version_ != 0) {
+ error_message_ << "--min_sdk_version is available only for compilation." << endl;
+ return;
+ }
+ // For other tasks, use "current"
+ min_sdk_version_ = MinSdkVersionFromString("current").value();
+ }
uint32_t default_ver = DefaultMinSdkVersionForLang(language_);
if (min_sdk_version_ == 0) { // --min_sdk_version flag not specified
diff --git a/options.h b/options.h
index a391332..2394395 100644
--- a/options.h
+++ b/options.h
@@ -19,6 +19,8 @@
#include <string>
#include <vector>
+#include <android-base/result.h>
+
#include "diagnostics.h"
namespace android {
@@ -211,6 +213,7 @@
};
std::string to_string(Options::Language language);
+android::base::Result<uint32_t> MinSdkVersionFromString(const std::string& str);
} // namespace aidl
} // namespace android