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());