Snap for 4662252 from 0805f17188b640d2078d1b381b78ca377c44ad08 to pi-release

Change-Id: If8c0f514b759e33a7adf210de632920b7f0480a1
diff --git a/aidl.cpp b/aidl.cpp
index 142f5f2..e0eef0d 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -742,7 +742,7 @@
   }
 
   return generate_java(output_file_name, options.input_file_name_.c_str(),
-                       interface.get(), types.get(), io_delegate);
+                       interface.get(), types.get(), io_delegate, options);
 }
 
 bool preprocess_aidl(const JavaOptions& options,
diff --git a/generate_java.cpp b/generate_java.cpp
index 30b9f2c..afa188a 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -56,8 +56,8 @@
 
 int generate_java(const string& filename, const string& originalSrc,
                   AidlInterface* iface, JavaTypeNamespace* types,
-                  const IoDelegate& io_delegate) {
-  Class* cl = generate_binder_interface_class(iface, types);
+                  const IoDelegate& io_delegate, const JavaOptions& options) {
+  Class* cl = generate_binder_interface_class(iface, types, options);
 
   Document* document = new Document(
       "" /* no comment */,
diff --git a/generate_java.h b/generate_java.h
index ed04ba1..59fed62 100644
--- a/generate_java.h
+++ b/generate_java.h
@@ -26,16 +26,19 @@
 namespace android {
 namespace aidl {
 
+class JavaOptions;
+
 namespace java {
 
 class JavaTypeNamespace;
 
 int generate_java(const std::string& filename, const std::string& originalSrc,
                   AidlInterface* iface, java::JavaTypeNamespace* types,
-                  const IoDelegate& io_delegate);
+                  const IoDelegate& io_delegate, const JavaOptions& options);
 
 android::aidl::java::Class* generate_binder_interface_class(
-    const AidlInterface* iface, java::JavaTypeNamespace* types);
+    const AidlInterface* iface, java::JavaTypeNamespace* types,
+    const JavaOptions& options);
 
 }  // namespace java
 
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index 8ca5d1b..ad993a8 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -20,9 +20,13 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <algorithm>
+#include <unordered_set>
+
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 
+#include "options.h"
 #include "type_java.h"
 
 using std::string;
@@ -47,10 +51,18 @@
   SwitchStatement* transact_switch;
   StatementBlock* transact_statements;
 
+  // Where onTransact cases should be generated as separate methods.
+  bool transact_outline;
+  // Specific methods that should be outlined when transact_outline is true.
+  std::unordered_set<const AidlMethod*> outline_methods;
+  // Number of all methods.
+  size_t all_method_count;
+
   // Finish generation. This will add a default case to the switch.
   void finish();
 
-  Expression* get_transact_descriptor(const JavaTypeNamespace* types);
+  Expression* get_transact_descriptor(const JavaTypeNamespace* types,
+                                      const AidlMethod* method);
 
  private:
   void make_as_interface(const InterfaceType* interfaceType,
@@ -65,6 +77,8 @@
                      JavaTypeNamespace* types)
     : Class() {
   transact_descriptor = nullptr;
+  transact_outline = false;
+  all_method_count = 0;  // Will be set when outlining may be enabled.
 
   this->comment = "/** Local-side IPC implementation stub class. */";
   this->modifiers = PUBLIC | ABSTRACT | STATIC;
@@ -138,9 +152,28 @@
   transact_statements->Add(this->transact_switch);
 }
 
-Expression* StubClass::get_transact_descriptor(const JavaTypeNamespace* types) {
-  // Store the descriptor literal into a local variable, in an effort to save
-  // const-string instructions in each switch case.
+// The the expression for the interface's descriptor to be used when
+// generating code for the given method. Null is acceptable for method
+// and stands for synthetic cases.
+Expression* StubClass::get_transact_descriptor(const JavaTypeNamespace* types,
+                                               const AidlMethod* method) {
+  if (transact_outline) {
+    if (method != nullptr) {
+      // When outlining, each outlined method needs its own literal.
+      if (outline_methods.count(method) != 0) {
+        return new LiteralExpression("DESCRIPTOR");
+      }
+    } else {
+      // Synthetic case. A small number is assumed. Use its own descriptor
+      // if there are only synthetic cases.
+      if (outline_methods.size() == all_method_count) {
+        return new LiteralExpression("DESCRIPTOR");
+      }
+    }
+  }
+
+  // When not outlining, store the descriptor literal into a local variable, in
+  // an effort to save const-string instructions in each switch case.
   if (transact_descriptor == nullptr) {
     transact_descriptor = new Variable(types->StringType(), "descriptor");
     transact_statements->Add(
@@ -322,7 +355,8 @@
   // interface token validation is the very first thing we do
   statements->Add(new MethodCall(transact_data,
                                  "enforceInterface", 1,
-                                 stubClass->get_transact_descriptor(types)));
+                                 stubClass->get_transact_descriptor(types,
+                                                                    &method)));
 
   // args
   VariableFactory stubArgs("_arg");
@@ -428,6 +462,51 @@
   stubClass->transact_switch->cases.push_back(c);
 }
 
+static void generate_stub_case_outline(const AidlMethod& method,
+                                       const std::string& transactCodeName,
+                                       bool oneway,
+                                       StubClass* stubClass,
+                                       JavaTypeNamespace* types) {
+  std::string outline_name = "onTransact$" + method.GetName() + "$";
+  // Generate an "outlined" method with the actual code.
+  {
+    Variable* transact_data = new Variable(types->ParcelType(), "data");
+    Variable* transact_reply = new Variable(types->ParcelType(), "reply");
+    Method* onTransact_case = new Method;
+    onTransact_case->modifiers = PRIVATE;
+    onTransact_case->returnType = types->BoolType();
+    onTransact_case->name = outline_name;
+    onTransact_case->parameters.push_back(transact_data);
+    onTransact_case->parameters.push_back(transact_reply);
+    onTransact_case->statements = new StatementBlock;
+    onTransact_case->exceptions.push_back(types->RemoteExceptionType());
+    stubClass->elements.push_back(onTransact_case);
+
+    generate_stub_code(method,
+                       transactCodeName,
+                       oneway,
+                       transact_data,
+                       transact_reply,
+                       types,
+                       onTransact_case->statements,
+                       stubClass);
+  }
+
+  // Generate the case dispatch.
+  {
+    Case* c = new Case(transactCodeName);
+
+    MethodCall* helper_call = new MethodCall(THIS_VALUE,
+                                             outline_name,
+                                             2,
+                                             stubClass->transact_data,
+                                             stubClass->transact_reply);
+    c->statements->Add(new ReturnStatement(helper_call));
+
+    stubClass->transact_switch->cases.push_back(c);
+  }
+}
+
 static std::unique_ptr<Method> generate_proxy_method(
     const AidlMethod& method,
     const std::string& transactCodeName,
@@ -566,7 +645,17 @@
   interface->elements.push_back(decl);
 
   // == the stub method ====================================================
-  generate_stub_case(method, transactCodeName, oneway, stubClass, types);
+  bool outline_stub = stubClass->transact_outline &&
+      stubClass->outline_methods.count(&method) != 0;
+  if (outline_stub) {
+    generate_stub_case_outline(method,
+                               transactCodeName,
+                               oneway,
+                               stubClass,
+                               types);
+  } else {
+    generate_stub_case(method, transactCodeName, oneway, stubClass, types);
+  }
 
   // == the proxy method ===================================================
   Method* proxy = generate_proxy_method(method,
@@ -582,7 +671,8 @@
   // the interface descriptor transaction handler
   Case* c = new Case("INTERFACE_TRANSACTION");
   c->statements->Add(new MethodCall(stub->transact_reply, "writeString", 1,
-                                    stub->get_transact_descriptor(types)));
+                                    stub->get_transact_descriptor(types,
+                                                                  nullptr)));
   c->statements->Add(new ReturnStatement(TRUE_VALUE));
   stub->transact_switch->cases.push_back(c);
 
@@ -598,8 +688,47 @@
   proxy->elements.push_back(getDesc);
 }
 
+// Check whether (some) methods in this interface should be "outlined," that
+// is, have specific onTransact methods for certain cases. Set up StubClass
+// metadata accordingly.
+//
+// Outlining will be enabled if the interface has more than outline_threshold
+// methods. In that case, the methods are sorted by number of arguments
+// (so that more "complex" methods come later), and the first non_outline_count
+// number of methods not outlined (are kept in the onTransact() method).
+//
+// Requirements: non_outline_count <= outline_threshold.
+static void compute_outline_methods(const AidlInterface* iface,
+                                    StubClass* stub,
+                                    size_t outline_threshold,
+                                    size_t non_outline_count) {
+  CHECK_LE(non_outline_count, outline_threshold);
+  // We'll outline (create sub methods) if there are more than min_methods
+  // cases.
+  stub->transact_outline = iface->GetMethods().size() > outline_threshold;
+  if (stub->transact_outline) {
+    stub->all_method_count = iface->GetMethods().size();
+    std::vector<const AidlMethod*> methods;
+    methods.reserve(iface->GetMethods().size());
+    for (const std::unique_ptr<AidlMethod>& ptr : iface->GetMethods()) {
+      methods.push_back(ptr.get());
+    }
+
+    std::stable_sort(
+        methods.begin(),
+        methods.end(),
+        [](const AidlMethod* m1, const AidlMethod* m2) {
+          return m1->GetArguments().size() < m2->GetArguments().size();
+        });
+
+    stub->outline_methods.insert(methods.begin() + non_outline_count,
+                                 methods.end());
+  }
+}
+
 Class* generate_binder_interface_class(const AidlInterface* iface,
-                                       JavaTypeNamespace* types) {
+                                       JavaTypeNamespace* types,
+                                       const JavaOptions& options) {
   const InterfaceType* interfaceType = iface->GetLanguageType<InterfaceType>();
 
   // the interface class
@@ -615,6 +744,11 @@
       new StubClass(interfaceType->GetStub(), interfaceType, types);
   interface->elements.push_back(stub);
 
+  compute_outline_methods(iface,
+                          stub,
+                          options.onTransact_outline_threshold_,
+                          options.onTransact_non_outline_count_);
+
   // the proxy inner class
   ProxyClass* proxy =
       new ProxyClass(types, interfaceType->GetProxy(), interfaceType);
@@ -632,8 +766,14 @@
   }
 
   // all the declared methods of the interface
+
   for (const auto& item : iface->GetMethods()) {
-    generate_methods(*item, interface, stub, proxy, item->GetId(), types);
+    generate_methods(*item,
+                     interface,
+                     stub,
+                     proxy,
+                     item->GetId(),
+                     types);
   }
   stub->finish();
 
diff --git a/options.h b/options.h
index 89a4412..6b3ac26 100644
--- a/options.h
+++ b/options.h
@@ -56,10 +56,18 @@
   bool dep_file_ninja_{false};
   std::vector<std::string> files_to_preprocess_;
 
+  // The following are for testability, but cannot be influenced on the command line.
+
+  // Threshold of interface methods to enable outlining of onTransact cases.
+  size_t onTransact_outline_threshold_{275u};
+  // Number of cases to _not_ outline, if outlining is enabled.
+  size_t onTransact_non_outline_count_{275u};
+
  private:
   JavaOptions() = default;
 
   FRIEND_TEST(EndToEndTest, IExampleInterface);
+  FRIEND_TEST(EndToEndTest, IExampleInterface_Outlining);
   FRIEND_TEST(AidlTest, FailOnParcelable);
   FRIEND_TEST(AidlTest, WritePreprocessedFile);
   FRIEND_TEST(AidlTest, WritesCorrectDependencyFile);
diff --git a/tests/end_to_end_tests.cpp b/tests/end_to_end_tests.cpp
index 480bfd9..344c4c2 100644
--- a/tests/end_to_end_tests.cpp
+++ b/tests/end_to_end_tests.cpp
@@ -92,6 +92,30 @@
   CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput);
 }
 
+TEST_F(EndToEndTest, IExampleInterface_Outlining) {
+  using namespace ::android::aidl::test_data::example_interface;
+
+  JavaOptions options;
+  options.fail_on_parcelable_ = true;
+  options.import_paths_.push_back("");
+  options.input_file_name_ = CanonicalNameToPath(kCanonicalName, ".aidl");
+  options.output_file_name_ = kJavaOutputPath;
+  options.dep_file_name_ = "an/arbitrary/path/to/deps.P";
+  options.onTransact_outline_threshold_ = 4;
+  options.onTransact_non_outline_count_ = 3;
+
+  // Load up our fake file system with data.
+  io_delegate_.SetFileContents(options.input_file_name_, kInterfaceDefinitionOutlining);
+  io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable",
+                                     {"Subclass1", "Subclass2"});
+  AddStubAidls(kImportedParcelables, kImportedInterfaces);
+
+  // Check that we parse correctly.
+  EXPECT_EQ(android::aidl::compile_aidl_to_java(options, io_delegate_), 0);
+  CheckFileContents(kJavaOutputPath, kExpectedJavaOutputOutlining);
+  CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput);
+}
+
 TEST_F(EndToEndTest, IPingResponderCpp) {
   using namespace ::android::aidl::test_data::ping_responder;
 
diff --git a/tests/test_data.h b/tests/test_data.h
index d3a5f6c..ae2c573 100644
--- a/tests/test_data.h
+++ b/tests/test_data.h
@@ -26,11 +26,13 @@
 extern const char kCanonicalName[];
 extern const char kJavaOutputPath[];
 extern const char kInterfaceDefinition[];
+extern const char kInterfaceDefinitionOutlining[];
 extern const char* kImportedParcelables[];
 extern const char* kImportedInterfaces[];
 
 extern const char kExpectedJavaDepsOutput[];
 extern const char kExpectedJavaOutput[];
+extern const char kExpectedJavaOutputOutlining[];
 
 }  // namespace example_interface
 
diff --git a/tests/test_data_example_interface.cpp b/tests/test_data_example_interface.cpp
index 81b919f..731efcd 100644
--- a/tests/test_data_example_interface.cpp
+++ b/tests/test_data_example_interface.cpp
@@ -67,6 +67,37 @@
 }
 )";
 
+const char kInterfaceDefinitionOutlining[] = R"(
+package android.test;
+
+import android.foo.ExampleParcelable;
+import android.test.CompoundParcelable;
+import android.bar.IAuxInterface;
+import android.test.IAuxInterface2;
+
+interface IExampleInterface {
+    const int EXAMPLE_CONSTANT = 3;
+    boolean isEnabled();
+    int getState(int a, int b);
+    String getAddress();
+
+    /* Test long comment */
+    ExampleParcelable[] getParcelables();
+
+    // Test short comment
+    boolean setScanMode(int mode, int duration);
+
+    /* Test long comment */
+    // And short comment
+    void registerBinder(IAuxInterface foo);
+    IExampleInterface getRecursiveBinder();
+
+    int takesAnInterface(in IAuxInterface2 arg);
+    int takesAParcelable(in CompoundParcelable.Subclass1 arg,
+                         inout CompoundParcelable.Subclass2 arg2);
+}
+)";
+
 const char kExpectedJavaDepsOutput[] =
 R"(some/path/to/output.java : \
   android/test/IExampleInterface.aidl \
@@ -120,16 +151,17 @@
 }
 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
 {
+java.lang.String descriptor = DESCRIPTOR;
 switch (code)
 {
 case INTERFACE_TRANSACTION:
 {
-reply.writeString(DESCRIPTOR);
+reply.writeString(descriptor);
 return true;
 }
 case TRANSACTION_isEnabled:
 {
-data.enforceInterface(DESCRIPTOR);
+data.enforceInterface(descriptor);
 boolean _result = this.isEnabled();
 reply.writeNoException();
 reply.writeInt(((_result)?(1):(0)));
@@ -137,7 +169,7 @@
 }
 case TRANSACTION_getState:
 {
-data.enforceInterface(DESCRIPTOR);
+data.enforceInterface(descriptor);
 int _result = this.getState();
 reply.writeNoException();
 reply.writeInt(_result);
@@ -145,7 +177,7 @@
 }
 case TRANSACTION_getAddress:
 {
-data.enforceInterface(DESCRIPTOR);
+data.enforceInterface(descriptor);
 java.lang.String _result = this.getAddress();
 reply.writeNoException();
 reply.writeString(_result);
@@ -153,7 +185,7 @@
 }
 case TRANSACTION_getParcelables:
 {
-data.enforceInterface(DESCRIPTOR);
+data.enforceInterface(descriptor);
 android.foo.ExampleParcelable[] _result = this.getParcelables();
 reply.writeNoException();
 reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
@@ -161,7 +193,7 @@
 }
 case TRANSACTION_setScanMode:
 {
-data.enforceInterface(DESCRIPTOR);
+data.enforceInterface(descriptor);
 int _arg0;
 _arg0 = data.readInt();
 int _arg1;
@@ -173,7 +205,7 @@
 }
 case TRANSACTION_registerBinder:
 {
-data.enforceInterface(DESCRIPTOR);
+data.enforceInterface(descriptor);
 android.bar.IAuxInterface _arg0;
 _arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder());
 this.registerBinder(_arg0);
@@ -182,7 +214,7 @@
 }
 case TRANSACTION_getRecursiveBinder:
 {
-data.enforceInterface(DESCRIPTOR);
+data.enforceInterface(descriptor);
 android.test.IExampleInterface _result = this.getRecursiveBinder();
 reply.writeNoException();
 reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
@@ -190,7 +222,7 @@
 }
 case TRANSACTION_takesAnInterface:
 {
-data.enforceInterface(DESCRIPTOR);
+data.enforceInterface(descriptor);
 android.test.IAuxInterface2 _arg0;
 _arg0 = android.test.IAuxInterface2.Stub.asInterface(data.readStrongBinder());
 int _result = this.takesAnInterface(_arg0);
@@ -200,7 +232,7 @@
 }
 case TRANSACTION_takesAParcelable:
 {
-data.enforceInterface(DESCRIPTOR);
+data.enforceInterface(descriptor);
 android.test.CompoundParcelable.Subclass1 _arg0;
 if ((0!=data.readInt())) {
 _arg0 = android.test.CompoundParcelable.Subclass1.CREATOR.createFromParcel(data);
@@ -227,9 +259,12 @@
 }
 return true;
 }
-}
+default:
+{
 return super.onTransact(code, data, reply, flags);
 }
+}
+}
 private static class Proxy implements android.test.IExampleInterface
 {
 private android.os.IBinder mRemote;
@@ -450,6 +485,408 @@
 }
 )";
 
+const char kExpectedJavaOutputOutlining[] =
+R"(/*
+ * This file is auto-generated.  DO NOT MODIFY.
+ * Original file: android/test/IExampleInterface.aidl
+ */
+package android.test;
+public interface IExampleInterface extends android.os.IInterface
+{
+/** Local-side IPC implementation stub class. */
+public static abstract class Stub extends android.os.Binder implements android.test.IExampleInterface
+{
+private static final java.lang.String DESCRIPTOR = "android.test.IExampleInterface";
+/** Construct the stub at attach it to the interface. */
+public Stub()
+{
+this.attachInterface(this, DESCRIPTOR);
+}
+/**
+ * Cast an IBinder object into an android.test.IExampleInterface interface,
+ * generating a proxy if needed.
+ */
+public static android.test.IExampleInterface asInterface(android.os.IBinder obj)
+{
+if ((obj==null)) {
+return null;
+}
+android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+if (((iin!=null)&&(iin instanceof android.test.IExampleInterface))) {
+return ((android.test.IExampleInterface)iin);
+}
+return new android.test.IExampleInterface.Stub.Proxy(obj);
+}
+@Override public android.os.IBinder asBinder()
+{
+return this;
+}
+@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
+{
+java.lang.String descriptor = DESCRIPTOR;
+switch (code)
+{
+case INTERFACE_TRANSACTION:
+{
+reply.writeString(descriptor);
+return true;
+}
+case TRANSACTION_isEnabled:
+{
+data.enforceInterface(descriptor);
+boolean _result = this.isEnabled();
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_getState:
+{
+return this.onTransact$getState$(data, reply);
+}
+case TRANSACTION_getAddress:
+{
+data.enforceInterface(descriptor);
+java.lang.String _result = this.getAddress();
+reply.writeNoException();
+reply.writeString(_result);
+return true;
+}
+case TRANSACTION_getParcelables:
+{
+data.enforceInterface(descriptor);
+android.foo.ExampleParcelable[] _result = this.getParcelables();
+reply.writeNoException();
+reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+return true;
+}
+case TRANSACTION_setScanMode:
+{
+return this.onTransact$setScanMode$(data, reply);
+}
+case TRANSACTION_registerBinder:
+{
+return this.onTransact$registerBinder$(data, reply);
+}
+case TRANSACTION_getRecursiveBinder:
+{
+return this.onTransact$getRecursiveBinder$(data, reply);
+}
+case TRANSACTION_takesAnInterface:
+{
+return this.onTransact$takesAnInterface$(data, reply);
+}
+case TRANSACTION_takesAParcelable:
+{
+return this.onTransact$takesAParcelable$(data, reply);
+}
+default:
+{
+return super.onTransact(code, data, reply, flags);
+}
+}
+}
+private static class Proxy implements android.test.IExampleInterface
+{
+private android.os.IBinder mRemote;
+Proxy(android.os.IBinder remote)
+{
+mRemote = remote;
+}
+@Override public android.os.IBinder asBinder()
+{
+return mRemote;
+}
+public java.lang.String getInterfaceDescriptor()
+{
+return DESCRIPTOR;
+}
+@Override public boolean isEnabled() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+boolean _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int getState(int a, int b) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeInt(a);
+_data.writeInt(b);
+mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public java.lang.String getAddress() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+java.lang.String _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readString();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+/* Test long comment */
+@Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+android.foo.ExampleParcelable[] _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0);
+_reply.readException();
+_result = _reply.createTypedArray(android.foo.ExampleParcelable.CREATOR);
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+// Test short comment
+
+@Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+boolean _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeInt(mode);
+_data.writeInt(duration);
+mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+/* Test long comment */// And short comment
+
+@Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeStrongBinder((((foo!=null))?(foo.asBinder()):(null)));
+mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0);
+_reply.readException();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+}
+@Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+android.test.IExampleInterface _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0);
+_reply.readException();
+_result = android.test.IExampleInterface.Stub.asInterface(_reply.readStrongBinder());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeStrongBinder((((arg!=null))?(arg.asBinder()):(null)));
+mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+if ((arg!=null)) {
+_data.writeInt(1);
+arg.writeToParcel(_data, 0);
+}
+else {
+_data.writeInt(0);
+}
+if ((arg2!=null)) {
+_data.writeInt(1);
+arg2.writeToParcel(_data, 0);
+}
+else {
+_data.writeInt(0);
+}
+mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+if ((0!=_reply.readInt())) {
+arg2.readFromParcel(_reply);
+}
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+}
+static final int TRANSACTION_isEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
+static final int TRANSACTION_getState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
+private boolean onTransact$getState$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException
+{
+data.enforceInterface(DESCRIPTOR);
+int _arg0;
+_arg0 = data.readInt();
+int _arg1;
+_arg1 = data.readInt();
+int _result = this.getState(_arg0, _arg1);
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+static final int TRANSACTION_getAddress = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
+static final int TRANSACTION_getParcelables = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
+static final int TRANSACTION_setScanMode = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
+private boolean onTransact$setScanMode$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException
+{
+data.enforceInterface(DESCRIPTOR);
+int _arg0;
+_arg0 = data.readInt();
+int _arg1;
+_arg1 = data.readInt();
+boolean _result = this.setScanMode(_arg0, _arg1);
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
+private boolean onTransact$registerBinder$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException
+{
+data.enforceInterface(DESCRIPTOR);
+android.bar.IAuxInterface _arg0;
+_arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder());
+this.registerBinder(_arg0);
+reply.writeNoException();
+return true;
+}
+static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
+private boolean onTransact$getRecursiveBinder$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.IExampleInterface _result = this.getRecursiveBinder();
+reply.writeNoException();
+reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
+return true;
+}
+static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
+private boolean onTransact$takesAnInterface$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.IAuxInterface2 _arg0;
+_arg0 = android.test.IAuxInterface2.Stub.asInterface(data.readStrongBinder());
+int _result = this.takesAnInterface(_arg0);
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
+private boolean onTransact$takesAParcelable$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.CompoundParcelable.Subclass1 _arg0;
+if ((0!=data.readInt())) {
+_arg0 = android.test.CompoundParcelable.Subclass1.CREATOR.createFromParcel(data);
+}
+else {
+_arg0 = null;
+}
+android.test.CompoundParcelable.Subclass2 _arg1;
+if ((0!=data.readInt())) {
+_arg1 = android.test.CompoundParcelable.Subclass2.CREATOR.createFromParcel(data);
+}
+else {
+_arg1 = null;
+}
+int _result = this.takesAParcelable(_arg0, _arg1);
+reply.writeNoException();
+reply.writeInt(_result);
+if ((_arg1!=null)) {
+reply.writeInt(1);
+_arg1.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+}
+else {
+reply.writeInt(0);
+}
+return true;
+}
+}
+public static final int EXAMPLE_CONSTANT = 3;
+public boolean isEnabled() throws android.os.RemoteException;
+public int getState(int a, int b) throws android.os.RemoteException;
+public java.lang.String getAddress() throws android.os.RemoteException;
+/* Test long comment */
+public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException;
+// Test short comment
+
+public boolean setScanMode(int mode, int duration) throws android.os.RemoteException;
+/* Test long comment */// And short comment
+
+public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException;
+public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException;
+public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException;
+public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException;
+}
+)";
+
 }  // namespace example_interface
 }  // namespace test_data
 }  // namespace aidl
diff --git a/tests/test_data_string_constants.cpp b/tests/test_data_string_constants.cpp
index 4674843..1fb84d2 100644
--- a/tests/test_data_string_constants.cpp
+++ b/tests/test_data_string_constants.cpp
@@ -69,16 +69,20 @@
 }
 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
 {
+java.lang.String descriptor = DESCRIPTOR;
 switch (code)
 {
 case INTERFACE_TRANSACTION:
 {
-reply.writeString(DESCRIPTOR);
+reply.writeString(descriptor);
 return true;
 }
-}
+default:
+{
 return super.onTransact(code, data, reply, flags);
 }
+}
+}
 private static class Proxy implements android.os.IStringConstants
 {
 private android.os.IBinder mRemote;