Descriptor annotation is added

The descriptor annotation allows the author of an AIDL interface to
override the interface descriptor token which by default is set to the
fully qualified name of the interface. For example,

package android.foo;

@Descriptor(value="android.bar.IWorld")
interface IHello {...}

The descriptor of the above interface is "android.bar.IWorld". If the
Descriptor annotation was missing, it would have been
"android.foo.IHello".

This would be useful when an already published interface has to be
renamed. By making the descriptor of the renamed interface to be the
descriptor of the interface before the renaiming, the interfaces -
before and after the renaming - can talk to each other.

Bug: 165712106
Test: atest aidl_unittests
Test: atest aidl_integration_test
Change-Id: I9cee8d883925f4d53adde4a131af450fb689b269
diff --git a/Android.bp b/Android.bp
index 62ecb6c..fae18d6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -304,6 +304,7 @@
         "tests/aidl_test_client_service_exceptions.cpp",
         "tests/aidl_test_client_defaultimpl.cpp",
         "tests/aidl_test_client_versioned_interface.cpp",
+        "tests/aidl_test_client_renamed_interface.cpp",
     ],
 }
 
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 763fb00..31dac88 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -134,6 +134,7 @@
       {AidlAnnotation::Type::JAVA_DEBUG, "JavaDebug", {}},
       {AidlAnnotation::Type::JAVA_ONLY_IMMUTABLE, "JavaOnlyImmutable", {}},
       {AidlAnnotation::Type::FIXED_SIZE, "FixedSize", {}},
+      {AidlAnnotation::Type::DESCRIPTOR, "Descriptor", {{"value", "String"}}},
   };
   return kSchemas;
 }
@@ -328,6 +329,23 @@
   return GetAnnotation(annotations_, AidlAnnotation::Type::JAVA_DEBUG);
 }
 
+std::string AidlAnnotatable::GetDescriptor() const {
+  auto annotation = GetAnnotation(annotations_, AidlAnnotation::Type::DESCRIPTOR);
+  if (annotation != nullptr) {
+    auto params = annotation->AnnotationParams(AidlConstantValueDecorator);
+    if (auto it = params.find("value"); it != params.end()) {
+      const string& value = it->second;
+
+      AIDL_FATAL_IF(value.size() < 2, this) << value;
+      AIDL_FATAL_IF(value[0] != '"', this) << value;
+      AIDL_FATAL_IF(value[value.length() - 1] != '"', this) << value;
+      std::string unquoted_value = value.substr(1, value.length() - 2);
+      return unquoted_value;
+    }
+  }
+  return "";
+}
+
 void AidlAnnotatable::DumpAnnotations(CodeWriter* writer) const {
   if (annotations_.empty()) return;
 
@@ -1133,7 +1151,8 @@
 
 std::set<AidlAnnotation::Type> AidlInterface::GetSupportedAnnotations() const {
   return {AidlAnnotation::Type::VINTF_STABILITY, AidlAnnotation::Type::UNSUPPORTED_APP_USAGE,
-          AidlAnnotation::Type::HIDE, AidlAnnotation::Type::JAVA_PASSTHROUGH};
+          AidlAnnotation::Type::HIDE, AidlAnnotation::Type::JAVA_PASSTHROUGH,
+          AidlAnnotation::Type::DESCRIPTOR};
 }
 
 bool AidlInterface::CheckValid(const AidlTypenames& typenames) const {
@@ -1238,5 +1257,13 @@
   return success;
 }
 
+std::string AidlInterface::GetDescriptor() const {
+  std::string annotatedDescriptor = AidlAnnotatable::GetDescriptor();
+  if (annotatedDescriptor != "") {
+    return annotatedDescriptor;
+  }
+  return GetCanonicalName();
+}
+
 AidlImport::AidlImport(const AidlLocation& location, const std::string& needed_class)
     : AidlNode(location), needed_class_(needed_class) {}
diff --git a/aidl_language.h b/aidl_language.h
index 74ef07d..64a8a0f 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -168,6 +168,7 @@
     JAVA_DEBUG,
     JAVA_ONLY_IMMUTABLE,
     FIXED_SIZE,
+    DESCRIPTOR,
   };
   static std::string TypeToString(Type type);
 
@@ -236,6 +237,7 @@
   bool IsStableApiParcelable(Options::Language lang) const;
   bool IsHide() const;
   bool IsJavaDebug() const;
+  std::string GetDescriptor() const;
 
   void DumpAnnotations(CodeWriter* writer) const;
 
@@ -872,6 +874,8 @@
   bool LanguageSpecificCheckValid(const AidlTypenames& typenames,
                                   Options::Language lang) const override;
 
+  std::string GetDescriptor() const;
+
  private:
   std::vector<std::unique_ptr<AidlMethod>> methods_;
   std::vector<std::unique_ptr<AidlConstantDeclaration>> constants_;
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index ecbee93..3f82e60 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -310,7 +310,7 @@
   const string method = "package a; @nullable interface IFoo { int f(); }";
   const string expected_stderr =
       "ERROR: a/IFoo.aidl:1.21-31: 'nullable' is not a supported annotation for this node. "
-      "It must be one of: Hide, UnsupportedAppUsage, VintfStability, JavaPassthrough\n";
+      "It must be one of: Hide, UnsupportedAppUsage, VintfStability, JavaPassthrough, Descriptor\n";
   CaptureStderr();
   EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", method, typenames_, GetLanguage(), &error));
   EXPECT_EQ(expected_stderr, GetCapturedStderr());
@@ -489,7 +489,8 @@
     EXPECT_NE(0, ::android::aidl::compile_aidl(java_options, io_delegate_));
     const std::string expected_stderr =
         "ERROR: a/IFoo.aidl:1.22-32: 'JavaDebug' is not a supported annotation for this node. "
-        "It must be one of: Hide, UnsupportedAppUsage, VintfStability, JavaPassthrough\n";
+        "It must be one of: Hide, UnsupportedAppUsage, VintfStability, JavaPassthrough, "
+        "Descriptor\n";
     EXPECT_EQ(expected_stderr, GetCapturedStderr());
   }
 
@@ -505,6 +506,17 @@
   }
 }
 
+TEST_P(AidlTest, ParseDescriptorAnnotation) {
+  AidlError error;
+  auto parse_result = Parse("IFoo.aidl", R"(@Descriptor(value="IBar") interface IFoo{})",
+                            typenames_, GetLanguage(), &error, {"--structured"});
+  ASSERT_EQ(AidlError::OK, error);
+  ASSERT_NE(nullptr, parse_result);
+  const AidlInterface* interface = parse_result->AsInterface();
+  ASSERT_NE(nullptr, interface);
+  ASSERT_EQ("IBar", interface->GetDescriptor());
+}
+
 TEST_P(AidlTest, AcceptsOnewayMethod) {
   const string oneway_method = "package a; interface IFoo { oneway void f(int a); }";
   EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, typenames_, GetLanguage()));
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index e510873..e1aef95 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -760,16 +760,12 @@
       HeaderFile(interface, ClassNames::CLIENT, false),
   };
 
-  string fq_name = ClassName(interface, ClassNames::INTERFACE);
-  if (!interface.GetPackage().empty()) {
-    fq_name = interface.GetPackage() + "." + fq_name;
-  }
-
   vector<unique_ptr<Declaration>> decls;
 
-  unique_ptr<MacroDecl> meta_if{new MacroDecl{
-      "DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE",
-      ArgList{vector<string>{ClassName(interface, ClassNames::BASE), '"' + fq_name + '"'}}}};
+  unique_ptr<MacroDecl> meta_if{
+      new MacroDecl{"DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE",
+                    ArgList{vector<string>{ClassName(interface, ClassNames::BASE),
+                                           '"' + interface.GetDescriptor() + '"'}}}};
   decls.push_back(std::move(meta_if));
 
   for (const auto& constant : interface.GetConstantDeclarations()) {
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index 6c2075f..b9c7674 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -920,14 +920,14 @@
   }
   auto descriptor = std::make_shared<Field>(
       STATIC | FINAL | PUBLIC, std::make_shared<Variable>("java.lang.String", "DESCRIPTOR"));
+  std::string name = iface->GetDescriptor();
   if (options.IsStructured()) {
     // mangle the interface name at build time and demangle it at runtime, to avoid
     // being renamed by jarjar. See b/153843174
-    std::string name = iface->GetCanonicalName();
     std::replace(name.begin(), name.end(), '.', '$');
     descriptor->value = "\"" + name + "\".replace('$', '.')";
   } else {
-    descriptor->value = "\"" + iface->GetCanonicalName() + "\"";
+    descriptor->value = "\"" + name + "\"";
   }
   classToAddDescriptor->elements.push_back(descriptor);
 }
diff --git a/generate_ndk.cpp b/generate_ndk.cpp
index 754642d..460967a 100644
--- a/generate_ndk.cpp
+++ b/generate_ndk.cpp
@@ -636,8 +636,8 @@
   const std::string bp_clazz = ClassName(defined_type, ClassNames::CLIENT);
 
   out << "// Source for " << clazz << "\n";
-  out << "const char* " << clazz << "::" << kDescriptor << " = \""
-      << defined_type.GetCanonicalName() << "\";\n";
+  out << "const char* " << clazz << "::" << kDescriptor << " = \"" << defined_type.GetDescriptor()
+      << "\";\n";
   out << clazz << "::" << clazz << "() {}\n";
   out << clazz << "::~" << clazz << "() {}\n";
   out << "\n";
diff --git a/tests/aidl_test_client_renamed_interface.cpp b/tests/aidl_test_client_renamed_interface.cpp
new file mode 100644
index 0000000..7bb2296
--- /dev/null
+++ b/tests/aidl_test_client_renamed_interface.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 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 "aidl_test_client.h"
+#include "gmock/gmock.h"
+
+#include <android/aidl/tests/INewName.h>
+#include <android/aidl/tests/IOldName.h>
+
+using android::IInterface;
+using android::String16;
+using android::aidl::tests::INewName;
+using android::aidl::tests::IOldName;
+using testing::Eq;
+
+class RenamedInterfaceTest : public AidlTest {
+ public:
+  void SetUp() override {
+    AidlTest::SetUp();
+
+    ASSERT_TRUE(service->GetOldNameInterface(&oldName).isOk());
+    ASSERT_TRUE(service->GetNewNameInterface(&newName).isOk());
+  }
+
+  sp<IOldName> oldName;
+  sp<INewName> newName;
+};
+
+TEST_F(RenamedInterfaceTest, oldAsOld) {
+  ASSERT_THAT(String16("android.aidl.tests.IOldName"), oldName->getInterfaceDescriptor());
+  String16 realName;
+  ASSERT_TRUE(oldName->RealName(&realName).isOk());
+  ASSERT_THAT(String16("OldName"), realName);
+}
+
+TEST_F(RenamedInterfaceTest, newAsNew) {
+  ASSERT_THAT(String16("android.aidl.tests.IOldName"), newName->getInterfaceDescriptor());
+  String16 realName;
+  ASSERT_TRUE(newName->RealName(&realName).isOk());
+  ASSERT_THAT(String16("NewName"), realName);
+}
+
+TEST_F(RenamedInterfaceTest, oldAsNew) {
+  sp<INewName> oldAsNew = INewName::asInterface(IInterface::asBinder(oldName));
+  ASSERT_THAT(String16("android.aidl.tests.IOldName"), oldAsNew->getInterfaceDescriptor());
+  String16 realName;
+  ASSERT_TRUE(oldAsNew->RealName(&realName).isOk());
+  ASSERT_THAT(String16("OldName"), realName);
+}
+
+TEST_F(RenamedInterfaceTest, newAsOld) {
+  sp<IOldName> newAsOld = IOldName::asInterface(IInterface::asBinder(newName));
+  ASSERT_THAT(String16("android.aidl.tests.IOldName"), newAsOld->getInterfaceDescriptor());
+  String16 realName;
+  ASSERT_TRUE(newAsOld->RealName(&realName).isOk());
+  ASSERT_THAT(String16("NewName"), realName);
+}
diff --git a/tests/aidl_test_service.cpp b/tests/aidl_test_service.cpp
index ecbfa05..40115ed 100644
--- a/tests/aidl_test_service.cpp
+++ b/tests/aidl_test_service.cpp
@@ -43,6 +43,9 @@
 #include "android/aidl/versioned/tests/BnFooInterface.h"
 #include "android/aidl/versioned/tests/IFooInterface.h"
 
+#include "android/aidl/tests/BnNewName.h"
+#include "android/aidl/tests/BnOldName.h"
+
 // Used implicitly.
 #undef LOG_TAG
 #define LOG_TAG "aidl_native_service"
@@ -69,11 +72,15 @@
 
 // Generated code:
 using android::aidl::tests::BnNamedCallback;
+using android::aidl::tests::BnNewName;
+using android::aidl::tests::BnOldName;
 using android::aidl::tests::BnTestService;
 using android::aidl::tests::ByteEnum;
 using android::aidl::tests::ConstantExpressionEnum;
 using android::aidl::tests::INamedCallback;
+using android::aidl::tests::INewName;
 using android::aidl::tests::IntEnum;
+using android::aidl::tests::IOldName;
 using android::aidl::tests::LongEnum;
 using android::aidl::tests::SimpleParcelable;
 using android::os::ParcelFileDescriptor;
@@ -111,6 +118,28 @@
   String16 name_;
 };
 
+class OldName : public BnOldName {
+ public:
+  OldName() = default;
+  ~OldName() = default;
+
+  Status RealName(String16* output) override {
+    *output = String16("OldName");
+    return Status::ok();
+  }
+};
+
+class NewName : public BnNewName {
+ public:
+  NewName() = default;
+  ~NewName() = default;
+
+  Status RealName(String16* output) override {
+    *output = String16("NewName");
+    return Status::ok();
+  }
+};
+
 class NativeService : public BnTestService {
  public:
   NativeService() {}
@@ -493,6 +522,16 @@
     LOG_ALWAYS_FATAL("UnimplementedMethod shouldn't be called");
   }
 
+  Status GetOldNameInterface(sp<IOldName>* ret) {
+    *ret = new OldName;
+    return Status::ok();
+  }
+
+  Status GetNewNameInterface(sp<INewName>* ret) {
+    *ret = new NewName;
+    return Status::ok();
+  }
+
   android::status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                uint32_t flags) override {
     if (code == ::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* UnimplementedMethod */) {
diff --git a/tests/android/aidl/tests/INewName.aidl b/tests/android/aidl/tests/INewName.aidl
new file mode 100644
index 0000000..d19500b
--- /dev/null
+++ b/tests/android/aidl/tests/INewName.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.aidl.tests;
+
+@Descriptor(value="android.aidl.tests.IOldName")
+interface INewName {
+    String RealName();
+}
diff --git a/tests/android/aidl/tests/IOldName.aidl b/tests/android/aidl/tests/IOldName.aidl
new file mode 100644
index 0000000..fb27513
--- /dev/null
+++ b/tests/android/aidl/tests/IOldName.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.aidl.tests;
+
+interface IOldName {
+    String RealName();
+}
diff --git a/tests/android/aidl/tests/ITestService.aidl b/tests/android/aidl/tests/ITestService.aidl
index 815801d..9296493 100644
--- a/tests/android/aidl/tests/ITestService.aidl
+++ b/tests/android/aidl/tests/ITestService.aidl
@@ -22,6 +22,8 @@
 import android.aidl.tests.LongEnum;
 import android.aidl.tests.SimpleParcelable;
 import android.aidl.tests.StructuredParcelable;
+import android.aidl.tests.IOldName;
+import android.aidl.tests.INewName;
 import android.os.PersistableBundle;
 
 interface ITestService {
@@ -207,4 +209,7 @@
   const int A55 = (2 + 3 - 4 * -7 / (10 % 3)) - 33 == 0;
   const int A56 = (2 + (-3&4 / 7)) == 2;
   const int A57 = (((((1 + 0)))));
+
+  IOldName GetOldNameInterface();
+  INewName GetNewNameInterface();
 }
diff --git a/tests/java_app/src/android/aidl/tests/TestServiceClient.java b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
index 33d5d2d..9b53517 100644
--- a/tests/java_app/src/android/aidl/tests/TestServiceClient.java
+++ b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
@@ -699,4 +699,27 @@
 
         assertThat(p.toString(), is(expected));
     }
+
+    @Test
+    public void testRenamedInterface() throws RemoteException {
+      IOldName oldAsOld = service.GetOldNameInterface();
+      assertNotNull(oldAsOld);
+      assertThat(oldAsOld.DESCRIPTOR, is("android.aidl.tests.IOldName"));
+      assertThat(oldAsOld.RealName(), is("OldName"));
+
+      INewName newAsNew = service.GetNewNameInterface();
+      assertNotNull(newAsNew);
+      assertThat(newAsNew.DESCRIPTOR, is("android.aidl.tests.IOldName"));
+      assertThat(oldAsOld.RealName(), is("OldName"));
+
+      IOldName newAsOld = IOldName.Stub.asInterface(service.GetNewNameInterface().asBinder());
+      assertNotNull(newAsOld);
+      assertThat(newAsOld.DESCRIPTOR, is("android.aidl.tests.IOldName"));
+      assertThat(newAsOld.RealName(), is("NewName"));
+
+      INewName oldAsNew = INewName.Stub.asInterface(service.GetOldNameInterface().asBinder());
+      assertNotNull(oldAsNew);
+      assertThat(oldAsNew.DESCRIPTOR, is("android.aidl.tests.IOldName"));
+      assertThat(oldAsNew.RealName(), is("OldName"));
+    }
 }