Allow parcelable defined from framework in stable aidl
To use stable aidl, every parcelable must be a structured parcelable.
But there is a need for the parcelable class defined in framework.
In this case, parcelable with @JavaOnlyStableParcelable is allowed.
For example,
- Foo.aidl:
@JavaOnlyStableParcelable parcelable Foo;
aidl --structured Foo.aidl succeed
Bug: 126469673
Test: m -j
Test: aidl with @JavaOnlyStableParcelable and --structured option
Change-Id: I634646e6d08746316477877600e496f2189a3f40
diff --git a/aidl.cpp b/aidl.cpp
index 52c4c86..227ba16 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -611,7 +611,11 @@
CHECK(defined_type != nullptr);
AidlParcelable* unstructuredParcelable = defined_type->AsUnstructuredParcelable();
if (unstructuredParcelable != nullptr) {
- if (options.IsStructured()) {
+ if (!unstructuredParcelable->CheckValid(typenames)) {
+ return AidlError::BAD_TYPE;
+ }
+ bool isStable = unstructuredParcelable->IsStableParcelable();
+ if (options.IsStructured() && !isStable) {
AIDL_ERROR(unstructuredParcelable)
<< "Cannot declared parcelable in a --structured interface. Parcelable must be defined "
"in AIDL directly.";
@@ -667,7 +671,8 @@
if (options.IsStructured()) {
typenames.IterateTypes([&](const AidlDefinedType& type) {
- if (type.AsUnstructuredParcelable() != nullptr) {
+ if (type.AsUnstructuredParcelable() != nullptr &&
+ !type.AsUnstructuredParcelable()->IsStableParcelable()) {
err = AidlError::NOT_STRUCTURED;
LOG(ERROR) << type.GetCanonicalName()
<< " is not structured, but this is a structured interface.";
diff --git a/aidl_language.cpp b/aidl_language.cpp
index d4d26b8..9ee3d05 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -72,8 +72,10 @@
static const string kUtf8InCpp("utf8InCpp");
static const string kUnsupportedAppUsage("UnsupportedAppUsage");
static const string kSystemApi("SystemApi");
+static const string kStableParcelable("JavaOnlyStableParcelable");
-static const set<string> kAnnotationNames{kNullable, kUtf8InCpp, kUnsupportedAppUsage, kSystemApi};
+static const set<string> kAnnotationNames{kNullable, kUtf8InCpp, kUnsupportedAppUsage, kSystemApi,
+ kStableParcelable};
AidlAnnotation* AidlAnnotation::Parse(const AidlLocation& location, const string& name) {
if (kAnnotationNames.find(name) == kAnnotationNames.end()) {
@@ -120,6 +122,10 @@
return HasAnnotation(annotations_, kSystemApi);
}
+bool AidlAnnotatable::IsStableParcelable() const {
+ return HasAnnotation(annotations_, kStableParcelable);
+}
+
string AidlAnnotatable::ToString() const {
vector<string> ret;
for (const auto& a : annotations_) {
@@ -621,6 +627,24 @@
}
}
+bool AidlParcelable::CheckValid(const AidlTypenames&) const {
+ static const std::set<string> allowed{kStableParcelable};
+ for (const auto& v : GetAnnotations()) {
+ if (allowed.find(v.GetName()) == allowed.end()) {
+ std::ostringstream stream;
+ stream << "Unstructured parcelable can contain only";
+ for (const string& kv : allowed) {
+ stream << " " << kv;
+ }
+ stream << ".";
+ AIDL_ERROR(this) << stream.str();
+ return false;
+ }
+ }
+
+ return true;
+}
+
void AidlParcelable::Write(CodeWriter* writer) const {
writer->Write("parcelable %s ;\n", GetName().c_str());
}
diff --git a/aidl_language.h b/aidl_language.h
index 887def2..1793f65 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -160,6 +160,7 @@
bool IsUtf8InCpp() const;
bool IsUnsupportedAppUsage() const;
bool IsSystemApi() const;
+ bool IsStableParcelable() const;
std::string ToString() const;
const vector<AidlAnnotation>& GetAnnotations() const { return annotations_; }
@@ -548,6 +549,8 @@
std::string GetCppName() const { return name_->GetColonName(); }
std::string GetCppHeader() const { return cpp_header_; }
+ bool CheckValid(const AidlTypenames& typenames) const override;
+
const AidlParcelable* AsParcelable() const override { return this; }
std::string GetPreprocessDeclarationName() const override { return "parcelable"; }
diff --git a/aidl_language_y.yy b/aidl_language_y.yy
index 442ffe5..3b2c586 100644
--- a/aidl_language_y.yy
+++ b/aidl_language_y.yy
@@ -168,11 +168,6 @@
{
$$ = $2;
- if ($$->AsUnstructuredParcelable() != nullptr && !$1->empty()) {
- AIDL_ERROR($$) << "unstructured parcelables cannot be annotated";
- ps->AddError();
- }
-
if ($1->size() > 0) {
// copy comments from annotation to decl
$2->SetComments($1->begin()->GetComments());