Add option for tracing AIDL calls.

This allows generating AIDL code that traces to the newly
introduced ATRACE_TAG_AIDL, for both c++ and Java targets.

The "::client" traces wrap the complete call, from entering
the proxy right until returning the result. As such, this
tag can be used to measure the complete duration of the IPC
call.

The "::server" traces wrap the actual execution of the
method on the server side, so it can be used to determine
the actual time the server took to complete the work.

Subtracting the "::server" slice from the corresponding
"::client" slice allows determining the overhead binder
itself introduced.

This is similar to how HIDL calls are traced.

Bug: 74416314
Test: aidl_unittest passed (incl new tests),
      verified atrace outpout
Change-Id: Id9a0207d53ebbdb6a21d8d96f56b8eee116bd477
diff --git a/aidl.cpp b/aidl.cpp
index e0eef0d..88a42f8 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -548,6 +548,7 @@
     const std::vector<std::string>& preprocessed_files,
     const std::vector<std::string>& import_paths,
     const std::string& input_file_name,
+    const bool generate_traces,
     const IoDelegate& io_delegate,
     TypeNamespace* types,
     std::unique_ptr<AidlInterface>* returned_interface,
@@ -633,6 +634,8 @@
 
   interface->SetLanguageType(types->GetInterfaceType(*interface));
 
+  interface->SetGenerateTraces(generate_traces);
+
   for (const auto& import : p.GetImports()) {
     // If we skipped an unresolved import above (see comment there) we'll have
     // an empty bucket here.
@@ -685,6 +688,7 @@
       std::vector<std::string>{},  // no preprocessed files
       options.ImportPaths(),
       options.InputFileName(),
+      options.ShouldGenTraces(),
       io_delegate,
       types.get(),
       &interface,
@@ -710,6 +714,7 @@
       options.preprocessed_files_,
       options.import_paths_,
       options.input_file_name_,
+      options.gen_traces_,
       io_delegate,
       types.get(),
       &interface,
diff --git a/aidl.h b/aidl.h
index 2e5b0ee..eb260c0 100644
--- a/aidl.h
+++ b/aidl.h
@@ -58,6 +58,7 @@
     const std::vector<std::string>& preprocessed_files,
     const std::vector<std::string>& import_paths,
     const std::string& input_file_name,
+    const bool generate_traces,
     const IoDelegate& io_delegate,
     TypeNamespace* types,
     std::unique_ptr<AidlInterface>* returned_interface,
diff --git a/aidl_language.h b/aidl_language.h
index 7982e76..4119628 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -345,6 +345,14 @@
     return reinterpret_cast<const T*>(language_type_);
   }
 
+  void SetGenerateTraces(bool generate_traces) {
+    generate_traces_ = generate_traces;
+  }
+
+  bool ShouldGenerateTraces() const {
+    return generate_traces_;
+  }
+
  private:
   std::string name_;
   std::string comments_;
@@ -356,6 +364,7 @@
   std::vector<std::string> package_;
 
   const android::aidl::ValidatableType* language_type_ = nullptr;
+  bool generate_traces_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(AidlInterface);
 };
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 570ecc7..597a766 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -80,6 +80,7 @@
         preprocessed_files_,
         import_paths_,
         path,
+        false, /* generate_traces */
         io_delegate_,
         types,
         &ret,
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 41e9fb4..7e8892b 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -52,6 +52,7 @@
 const char kReplyVarName[] = "_aidl_reply";
 const char kReturnVarName[] = "_aidl_return";
 const char kStatusVarName[] = "_aidl_status";
+const char kTraceVarName[] = "_aidl_trace";
 const char kAndroidParcelLiteral[] = "::android::Parcel";
 const char kAndroidStatusLiteral[] = "::android::status_t";
 const char kAndroidStatusOk[] = "::android::OK";
@@ -61,6 +62,7 @@
 const char kParcelHeader[] = "binder/Parcel.h";
 const char kStatusHeader[] = "binder/Status.h";
 const char kString16Header[] = "utils/String16.h";
+const char kTraceHeader[] = "utils/Trace.h";
 const char kStrongPointerHeader[] = "utils/StrongPointer.h";
 
 unique_ptr<AstNode> BreakOnStatusNotOk() {
@@ -271,6 +273,12 @@
   // We unconditionally return a Status object.
   b->AddLiteral(StringPrintf("%s %s", kBinderStatusLiteral, kStatusVarName));
 
+  if (interface.ShouldGenerateTraces()) {
+    b->AddLiteral(
+        StringPrintf("ScopedTrace %s(ATRACE_TAG_AIDL, \"%s::%s::cppClient\")",
+        kTraceVarName, interface.GetName().c_str(), method.GetName().c_str()));
+  }
+
   // Add the name of the interface we're hoping to call.
   b->AddStatement(new Assignment(
       kAndroidStatusVarName,
@@ -378,6 +386,7 @@
   b->AddLiteral(
       StringPrintf("%s.setFromStatusT(%s)", kStatusVarName,
                    kAndroidStatusVarName));
+
   b->AddLiteral(StringPrintf("return %s", kStatusVarName));
 
   return unique_ptr<Declaration>(ret.release());
@@ -417,6 +426,7 @@
 namespace {
 
 bool HandleServerTransaction(const TypeNamespace& types,
+                             const AidlInterface& interface,
                              const AidlMethod& method,
                              StatementBlock* b) {
   // Declare all the parameters now.  In the common case, we expect no errors
@@ -469,6 +479,14 @@
     }
   }
 
+  if (interface.ShouldGenerateTraces()) {
+    b->AddStatement(new Statement(new MethodCall("atrace_begin",
+        ArgList{{"ATRACE_TAG_AIDL",
+        StringPrintf("\"%s::%s::cppServer\"",
+                     interface.GetName().c_str(),
+                     method.GetName().c_str())}})));
+  }
+
   // Call the actual method.  This is implemented by the subclass.
   vector<unique_ptr<AstNode>> status_args;
   status_args.emplace_back(new MethodCall(
@@ -478,6 +496,11 @@
       StringPrintf("%s %s", kBinderStatusLiteral, kStatusVarName),
       ArgList(std::move(status_args)))));
 
+  if (interface.ShouldGenerateTraces()) {
+    b->AddStatement(new Statement(new MethodCall("atrace_end",
+                                                 "ATRACE_TAG_AIDL")));
+  }
+
   // Write exceptions during transaction handling to parcel.
   if (!method.IsOneway()) {
     b->AddStatement(new Assignment(
@@ -551,7 +574,7 @@
     StatementBlock* b = s->AddCase("Call::" + UpperCase(method->GetName()));
     if (!b) { return nullptr; }
 
-    if (!HandleServerTransaction(types, *method, b)) { return nullptr; }
+    if (!HandleServerTransaction(types, interface, *method, b)) { return nullptr; }
   }
 
   // The switch statement has a default case which defers to the super class.
@@ -727,6 +750,11 @@
   if (!interface.GetStringConstants().empty()) {
     includes.insert(kString16Header);
   }
+
+  if (interface.ShouldGenerateTraces()) {
+    includes.insert(kTraceHeader);
+  }
+
   for (const auto& constant : interface.GetStringConstants()) {
     unique_ptr<MethodDecl> getter(new MethodDecl(
           "const ::android::String16&", constant->GetName(),
diff --git a/generate_cpp_unittest.cpp b/generate_cpp_unittest.cpp
index 50bfd9c..32e9362 100644
--- a/generate_cpp_unittest.cpp
+++ b/generate_cpp_unittest.cpp
@@ -378,6 +378,304 @@
 }  // namespace android
 )";
 
+const char kExpectedComplexTypeClientWithTraceSourceOutput[] =
+R"(#include <android/os/BpComplexTypeInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+namespace os {
+
+BpComplexTypeInterface::BpComplexTypeInterface(const ::android::sp<::android::IBinder>& _aidl_impl)
+    : BpInterface<IComplexTypeInterface>(_aidl_impl){
+}
+
+::android::binder::Status BpComplexTypeInterface::Send(const ::std::unique_ptr<::std::vector<int32_t>>& goes_in, ::std::vector<double>* goes_in_and_out, ::std::vector<bool>* goes_out, ::std::vector<int32_t>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::Send::cppClient");
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeInt32Vector(goes_in);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeDoubleVector(*goes_in_and_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeVectorSize(*goes_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::SEND, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readInt32Vector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_reply.readDoubleVector(goes_in_and_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_reply.readBoolVector(goes_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::Piff(int32_t times) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::Piff::cppClient");
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeInt32(times);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::PIFF, _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::TakesABinder(const ::android::sp<::foo::IFooType>& f, ::android::sp<::foo::IFooType>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesABinder::cppClient");
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeStrongBinder(::foo::IFooType::asBinder(f));
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::TAKESABINDER, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readStrongBinder(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::NullableBinder(::android::sp<::foo::IFooType>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::NullableBinder::cppClient");
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::NULLABLEBINDER, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::StringListMethod(const ::std::vector<::android::String16>& input, ::std::vector<::android::String16>* output, ::std::vector<::android::String16>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::StringListMethod::cppClient");
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeString16Vector(input);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::STRINGLISTMETHOD, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readString16Vector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_reply.readString16Vector(output);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::BinderListMethod(const ::std::vector<::android::sp<::android::IBinder>>& input, ::std::vector<::android::sp<::android::IBinder>>* output, ::std::vector<::android::sp<::android::IBinder>>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::BinderListMethod::cppClient");
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeStrongBinderVector(input);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::BINDERLISTMETHOD, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readStrongBinderVector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_reply.readStrongBinderVector(output);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::TakesAFileDescriptor(const ::android::base::unique_fd& f, ::android::base::unique_fd* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesAFileDescriptor::cppClient");
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeUniqueFileDescriptor(f);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::TAKESAFILEDESCRIPTOR, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readUniqueFileDescriptor(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::TakesAFileDescriptorArray(const ::std::vector<::android::base::unique_fd>& f, ::std::vector<::android::base::unique_fd>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesAFileDescriptorArray::cppClient");
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeUniqueFileDescriptorVector(f);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::TAKESAFILEDESCRIPTORARRAY, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readUniqueFileDescriptorVector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+}  // namespace os
+
+}  // namespace android
+)";
+
 const char kExpectedComplexTypeServerHeaderOutput[] =
 R"(#ifndef AIDL_GENERATED_ANDROID_OS_BN_COMPLEX_TYPE_INTERFACE_H_
 #define AIDL_GENERATED_ANDROID_OS_BN_COMPLEX_TYPE_INTERFACE_H_
@@ -648,6 +946,269 @@
 }  // namespace android
 )";
 
+const char kExpectedComplexTypeServerWithTraceSourceOutput[] =
+R"(#include <android/os/BnComplexTypeInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+namespace os {
+
+::android::status_t BnComplexTypeInterface::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
+::android::status_t _aidl_ret_status = ::android::OK;
+switch (_aidl_code) {
+case Call::SEND:
+{
+::std::unique_ptr<::std::vector<int32_t>> in_goes_in;
+::std::vector<double> in_goes_in_and_out;
+::std::vector<bool> out_goes_out;
+::std::vector<int32_t> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readInt32Vector(&in_goes_in);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_data.readDoubleVector(&in_goes_in_and_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_data.resizeOutVector(&out_goes_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::Send::cppServer");
+::android::binder::Status _aidl_status(Send(in_goes_in, &in_goes_in_and_out, &out_goes_out, &_aidl_return));
+atrace_end(ATRACE_TAG_AIDL);
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeInt32Vector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeDoubleVector(in_goes_in_and_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeBoolVector(out_goes_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::PIFF:
+{
+int32_t in_times;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readInt32(&in_times);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::Piff::cppServer");
+::android::binder::Status _aidl_status(Piff(in_times));
+atrace_end(ATRACE_TAG_AIDL);
+}
+break;
+case Call::TAKESABINDER:
+{
+::android::sp<::foo::IFooType> in_f;
+::android::sp<::foo::IFooType> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readStrongBinder(&in_f);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesABinder::cppServer");
+::android::binder::Status _aidl_status(TakesABinder(in_f, &_aidl_return));
+atrace_end(ATRACE_TAG_AIDL);
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeStrongBinder(::foo::IFooType::asBinder(_aidl_return));
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::NULLABLEBINDER:
+{
+::android::sp<::foo::IFooType> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::NullableBinder::cppServer");
+::android::binder::Status _aidl_status(NullableBinder(&_aidl_return));
+atrace_end(ATRACE_TAG_AIDL);
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeStrongBinder(::foo::IFooType::asBinder(_aidl_return));
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::STRINGLISTMETHOD:
+{
+::std::vector<::android::String16> in_input;
+::std::vector<::android::String16> out_output;
+::std::vector<::android::String16> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readString16Vector(&in_input);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::StringListMethod::cppServer");
+::android::binder::Status _aidl_status(StringListMethod(in_input, &out_output, &_aidl_return));
+atrace_end(ATRACE_TAG_AIDL);
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeString16Vector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeString16Vector(out_output);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::BINDERLISTMETHOD:
+{
+::std::vector<::android::sp<::android::IBinder>> in_input;
+::std::vector<::android::sp<::android::IBinder>> out_output;
+::std::vector<::android::sp<::android::IBinder>> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readStrongBinderVector(&in_input);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::BinderListMethod::cppServer");
+::android::binder::Status _aidl_status(BinderListMethod(in_input, &out_output, &_aidl_return));
+atrace_end(ATRACE_TAG_AIDL);
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeStrongBinderVector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeStrongBinderVector(out_output);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::TAKESAFILEDESCRIPTOR:
+{
+::android::base::unique_fd in_f;
+::android::base::unique_fd _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readUniqueFileDescriptor(&in_f);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesAFileDescriptor::cppServer");
+::android::binder::Status _aidl_status(TakesAFileDescriptor(in_f, &_aidl_return));
+atrace_end(ATRACE_TAG_AIDL);
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeUniqueFileDescriptor(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::TAKESAFILEDESCRIPTORARRAY:
+{
+::std::vector<::android::base::unique_fd> in_f;
+::std::vector<::android::base::unique_fd> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readUniqueFileDescriptorVector(&in_f);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesAFileDescriptorArray::cppServer");
+::android::binder::Status _aidl_status(TakesAFileDescriptorArray(in_f, &_aidl_return));
+atrace_end(ATRACE_TAG_AIDL);
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeUniqueFileDescriptorVector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+default:
+{
+_aidl_ret_status = ::android::BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
+}
+break;
+}
+if (_aidl_ret_status == ::android::UNEXPECTED_NULL) {
+_aidl_ret_status = ::android::binder::Status::fromExceptionCode(::android::binder::Status::EX_NULL_POINTER).writeToParcel(_aidl_reply);
+}
+return _aidl_ret_status;
+}
+
+}  // namespace os
+
+}  // namespace android
+)";
+
 const char kExpectedComplexTypeInterfaceHeaderOutput[] =
 R"(#ifndef AIDL_GENERATED_ANDROID_OS_I_COMPLEX_TYPE_INTERFACE_H_
 #define AIDL_GENERATED_ANDROID_OS_I_COMPLEX_TYPE_INTERFACE_H_
@@ -734,6 +1295,7 @@
         {},  // no preprocessed files
         {"."},
         file_path_,
+        false, // generate_traces
         io_delegate_,
         &types_,
         &ret,
@@ -789,6 +1351,14 @@
   Compare(doc.get(), kExpectedComplexTypeClientSourceOutput);
 }
 
+TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientSourceWithTrace) {
+  unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  interface->SetGenerateTraces(true);
+  unique_ptr<Document> doc = internals::BuildClientSource(types_, *interface);
+  Compare(doc.get(), kExpectedComplexTypeClientWithTraceSourceOutput);
+}
+
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerHeader) {
   unique_ptr<AidlInterface> interface = Parse();
   ASSERT_NE(interface, nullptr);
@@ -803,6 +1373,14 @@
   Compare(doc.get(), kExpectedComplexTypeServerSourceOutput);
 }
 
+TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerSourceWithTrace) {
+  unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  interface->SetGenerateTraces(true);
+  unique_ptr<Document> doc = internals::BuildServerSource(types_, *interface);
+  Compare(doc.get(), kExpectedComplexTypeServerWithTraceSourceOutput);
+}
+
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceHeader) {
   unique_ptr<AidlInterface> interface = Parse();
   ASSERT_NE(interface, nullptr);
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index ad993a8..522715c 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -342,7 +342,8 @@
   return decl;
 }
 
-static void generate_stub_code(const AidlMethod& method,
+static void generate_stub_code(const AidlInterface& iface,
+                               const AidlMethod& method,
                                const std::string& transactCodeName,
                                bool oneway,
                                Variable* transact_data,
@@ -350,6 +351,8 @@
                                JavaTypeNamespace* types,
                                StatementBlock* statements,
                                StubClass* stubClass) {
+  TryStatement* tryStatement = nullptr;
+  FinallyStatement* finallyStatement = nullptr;
   MethodCall* realCall = new MethodCall(THIS_VALUE, method.GetName());
 
   // interface token validation is the very first thing we do
@@ -391,9 +394,31 @@
     }
   }
 
+  if (iface.ShouldGenerateTraces()) {
+    // try and finally, but only when generating trace code
+    tryStatement = new TryStatement();
+    finallyStatement = new FinallyStatement();
+
+    tryStatement->statements->Add(new MethodCall(
+        new LiteralExpression("android.os.Trace"), "traceBegin", 2,
+        new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"),
+        new StringLiteralExpression(iface.GetName() + "::"
+            + method.GetName() + "::server")));
+
+    finallyStatement->statements->Add(new MethodCall(
+        new LiteralExpression("android.os.Trace"), "traceEnd", 1,
+        new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL")));
+  }
+
   // the real call
   if (method.GetType().GetName() == "void") {
-    statements->Add(realCall);
+    if (iface.ShouldGenerateTraces()) {
+      statements->Add(tryStatement);
+      tryStatement->statements->Add(realCall);
+      statements->Add(finallyStatement);
+    } else {
+      statements->Add(realCall);
+    }
 
     if (!oneway) {
       // report that there were no exceptions
@@ -406,7 +431,14 @@
         new Variable(method.GetType().GetLanguageType<Type>(),
                      "_result",
                      method.GetType().IsArray() ? 1 : 0);
-    statements->Add(new VariableDeclaration(_result, realCall));
+    if (iface.ShouldGenerateTraces()) {
+      statements->Add(new VariableDeclaration(_result));
+      statements->Add(tryStatement);
+      tryStatement->statements->Add(new Assignment(_result, realCall));
+      statements->Add(finallyStatement);
+    } else {
+      statements->Add(new VariableDeclaration(_result, realCall));
+    }
 
     if (!oneway) {
       // report that there were no exceptions
@@ -443,14 +475,16 @@
 }
 
 
-static void generate_stub_case(const AidlMethod& method,
+static void generate_stub_case(const AidlInterface& iface,
+                               const AidlMethod& method,
                                const std::string& transactCodeName,
                                bool oneway,
                                StubClass* stubClass,
                                JavaTypeNamespace* types) {
   Case* c = new Case(transactCodeName);
 
-  generate_stub_code(method,
+  generate_stub_code(iface,
+                     method,
                      transactCodeName,
                      oneway,
                      stubClass->transact_data,
@@ -462,7 +496,8 @@
   stubClass->transact_switch->cases.push_back(c);
 }
 
-static void generate_stub_case_outline(const AidlMethod& method,
+static void generate_stub_case_outline(const AidlInterface& iface,
+                                       const AidlMethod& method,
                                        const std::string& transactCodeName,
                                        bool oneway,
                                        StubClass* stubClass,
@@ -482,7 +517,8 @@
     onTransact_case->exceptions.push_back(types->RemoteExceptionType());
     stubClass->elements.push_back(onTransact_case);
 
-    generate_stub_code(method,
+    generate_stub_code(iface,
+                       method,
                        transactCodeName,
                        oneway,
                        transact_data,
@@ -508,6 +544,7 @@
 }
 
 static std::unique_ptr<Method> generate_proxy_method(
+    const AidlInterface& iface,
     const AidlMethod& method,
     const std::string& transactCodeName,
     bool oneway,
@@ -552,6 +589,14 @@
   FinallyStatement* finallyStatement = new FinallyStatement();
   proxy->statements->Add(finallyStatement);
 
+  if (iface.ShouldGenerateTraces()) {
+    tryStatement->statements->Add(new MethodCall(
+          new LiteralExpression("android.os.Trace"), "traceBegin", 2,
+          new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"),
+          new StringLiteralExpression(iface.GetName() + "::" +
+                                      method.GetName() + "::client")));
+  }
+
   // the interface identifier token: the DESCRIPTOR constant, marshalled as a
   // string
   tryStatement->statements->Add(new MethodCall(
@@ -615,6 +660,12 @@
   }
   finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
 
+  if (iface.ShouldGenerateTraces()) {
+    finallyStatement->statements->Add(new MethodCall(
+        new LiteralExpression("android.os.Trace"), "traceEnd", 1,
+        new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL")));
+  }
+
   if (_result != NULL) {
     proxy->statements->Add(new ReturnStatement(_result));
   }
@@ -622,7 +673,8 @@
   return proxy;
 }
 
-static void generate_methods(const AidlMethod& method,
+static void generate_methods(const AidlInterface& iface,
+                             const AidlMethod& method,
                              Class* interface,
                              StubClass* stubClass,
                              ProxyClass* proxyClass,
@@ -648,17 +700,19 @@
   bool outline_stub = stubClass->transact_outline &&
       stubClass->outline_methods.count(&method) != 0;
   if (outline_stub) {
-    generate_stub_case_outline(method,
+    generate_stub_case_outline(iface,
+                               method,
                                transactCodeName,
                                oneway,
                                stubClass,
                                types);
   } else {
-    generate_stub_case(method, transactCodeName, oneway, stubClass, types);
+    generate_stub_case(iface, method, transactCodeName, oneway, stubClass, types);
   }
 
   // == the proxy method ===================================================
-  Method* proxy = generate_proxy_method(method,
+  Method* proxy = generate_proxy_method(iface,
+                                        method,
                                         transactCodeName,
                                         oneway,
                                         proxyClass,
@@ -768,7 +822,8 @@
   // all the declared methods of the interface
 
   for (const auto& item : iface->GetMethods()) {
-    generate_methods(*item,
+    generate_methods(*iface,
+                     *item,
                      interface,
                      stub,
                      proxy,
diff --git a/options.cpp b/options.cpp
index 72c7575..3ed110b 100644
--- a/options.cpp
+++ b/options.cpp
@@ -48,6 +48,9 @@
           "   -p<FILE>   file created by --preprocess to import.\n"
           "   -o<FOLDER> base output folder for generated files.\n"
           "   -b         fail when trying to compile a parcelable.\n"
+          "   -t         include tracing code for systrace. Note that if either "
+          "the client or server code is not auto-generated by this tool, that "
+          "part will not be traced.\n"
           "\n"
           "INPUT:\n"
           "   An aidl interface file.\n"
@@ -126,6 +129,8 @@
       options->fail_on_parcelable_ = true;
     } else if (strcmp(s, "-ninja") == 0) {
       options->dep_file_ninja_ = true;
+    } else if (strcmp(s, "-t") == 0) {
+      options->gen_traces_ = true;
     } else {
       // s[1] is not known
       fprintf(stderr, "unknown option (%d): %s\n", i, s);
@@ -190,6 +195,9 @@
        << "OPTIONS:" << endl
        << "   -I<DIR>   search path for import statements" << endl
        << "   -d<FILE>  generate dependency file" << endl
+       << "   -t        include tracing code for systrace. Note that if the "
+          "client or server code is not auto-generated by this tool, that part "
+          "will not be traced." << endl
        << "   -ninja    generate dependency file in a format ninja "
           "understands" << endl
        << endl
@@ -224,6 +232,8 @@
       options->import_paths_.push_back(the_rest);
     } else if (s[1] == 'd') {
       options->dep_file_name_ = the_rest;
+    } else if (s[1] == 't') {
+      options->gen_traces_ = true;
     } else if (strcmp(s, "-ninja") == 0) {
       options->dep_file_ninja_ = true;
     } else {
diff --git a/options.h b/options.h
index 6b3ac26..11f3525 100644
--- a/options.h
+++ b/options.h
@@ -54,6 +54,7 @@
   std::string dep_file_name_;
   bool auto_dep_file_{false};
   bool dep_file_ninja_{false};
+  bool gen_traces_{false};
   std::vector<std::string> files_to_preprocess_;
 
   // The following are for testability, but cannot be influenced on the command line.
@@ -67,6 +68,7 @@
   JavaOptions() = default;
 
   FRIEND_TEST(EndToEndTest, IExampleInterface);
+  FRIEND_TEST(EndToEndTest, IExampleInterface_WithTrace);
   FRIEND_TEST(EndToEndTest, IExampleInterface_Outlining);
   FRIEND_TEST(AidlTest, FailOnParcelable);
   FRIEND_TEST(AidlTest, WritePreprocessedFile);
@@ -94,6 +96,7 @@
   std::vector<std::string> ImportPaths() const { return import_paths_; }
   std::string DependencyFilePath() const { return dep_file_name_; }
   bool DependencyFileNinja() const { return dep_file_ninja_; }
+  bool ShouldGenTraces() const { return gen_traces_; }
 
  private:
   CppOptions() = default;
@@ -103,6 +106,7 @@
   std::string output_header_dir_;
   std::string output_file_name_;
   std::string dep_file_name_;
+  bool gen_traces_{false};
   bool dep_file_ninja_{false};
 
   FRIEND_TEST(CppOptionsTests, ParsesCompileCpp);
diff --git a/tests/end_to_end_tests.cpp b/tests/end_to_end_tests.cpp
index 344c4c2..555d8dc 100644
--- a/tests/end_to_end_tests.cpp
+++ b/tests/end_to_end_tests.cpp
@@ -92,6 +92,29 @@
   CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput);
 }
 
+TEST_F(EndToEndTest, IExampleInterface_WithTrace) {
+  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.gen_traces_ = true;
+
+  // Load up our fake file system with data.
+  io_delegate_.SetFileContents(options.input_file_name_, kInterfaceDefinition);
+  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, kExpectedJavaOutputWithTrace);
+  CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput);
+}
+
 TEST_F(EndToEndTest, IExampleInterface_Outlining) {
   using namespace ::android::aidl::test_data::example_interface;
 
diff --git a/tests/test_data.h b/tests/test_data.h
index ae2c573..0b5aaf0 100644
--- a/tests/test_data.h
+++ b/tests/test_data.h
@@ -33,6 +33,7 @@
 extern const char kExpectedJavaDepsOutput[];
 extern const char kExpectedJavaOutput[];
 extern const char kExpectedJavaOutputOutlining[];
+extern const char kExpectedJavaOutputWithTrace[];
 
 }  // namespace example_interface
 
diff --git a/tests/test_data_example_interface.cpp b/tests/test_data_example_interface.cpp
index 731efcd..9b0e0ee 100644
--- a/tests/test_data_example_interface.cpp
+++ b/tests/test_data_example_interface.cpp
@@ -485,6 +485,458 @@
 }
 )";
 
+const char kExpectedJavaOutputWithTrace[] =
+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;
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::isEnabled::server");
+_result = this.isEnabled();
+}
+finally {
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_getState:
+{
+data.enforceInterface(descriptor);
+int _result;
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getState::server");
+_result = this.getState();
+}
+finally {
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+case TRANSACTION_getAddress:
+{
+data.enforceInterface(descriptor);
+java.lang.String _result;
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getAddress::server");
+_result = this.getAddress();
+}
+finally {
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+reply.writeNoException();
+reply.writeString(_result);
+return true;
+}
+case TRANSACTION_getParcelables:
+{
+data.enforceInterface(descriptor);
+android.foo.ExampleParcelable[] _result;
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getParcelables::server");
+_result = this.getParcelables();
+}
+finally {
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+reply.writeNoException();
+reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+return true;
+}
+case TRANSACTION_setScanMode:
+{
+data.enforceInterface(descriptor);
+int _arg0;
+_arg0 = data.readInt();
+int _arg1;
+_arg1 = data.readInt();
+boolean _result;
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::setScanMode::server");
+_result = this.setScanMode(_arg0, _arg1);
+}
+finally {
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_registerBinder:
+{
+data.enforceInterface(descriptor);
+android.bar.IAuxInterface _arg0;
+_arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder());
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::registerBinder::server");
+this.registerBinder(_arg0);
+}
+finally {
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+reply.writeNoException();
+return true;
+}
+case TRANSACTION_getRecursiveBinder:
+{
+data.enforceInterface(descriptor);
+android.test.IExampleInterface _result;
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getRecursiveBinder::server");
+_result = this.getRecursiveBinder();
+}
+finally {
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+reply.writeNoException();
+reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
+return true;
+}
+case TRANSACTION_takesAnInterface:
+{
+data.enforceInterface(descriptor);
+android.test.IAuxInterface2 _arg0;
+_arg0 = android.test.IAuxInterface2.Stub.asInterface(data.readStrongBinder());
+int _result;
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::takesAnInterface::server");
+_result = this.takesAnInterface(_arg0);
+}
+finally {
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+case TRANSACTION_takesAParcelable:
+{
+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;
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::takesAParcelable::server");
+_result = this.takesAParcelable(_arg0, _arg1);
+}
+finally {
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+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;
+}
+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 {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::isEnabled::client");
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+return _result;
+}
+@Override public int getState() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getState::client");
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+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 {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getAddress::client");
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readString();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+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 {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getParcelables::client");
+_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();
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+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 {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::setScanMode::client");
+_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();
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+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 {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::registerBinder::client");
+_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();
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+}
+@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 {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getRecursiveBinder::client");
+_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();
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+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 {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::takesAnInterface::client");
+_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();
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+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 {
+android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::takesAParcelable::client");
+_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();
+android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL);
+}
+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);
+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);
+static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
+static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
+static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
+static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
+}
+public static final int EXAMPLE_CONSTANT = 3;
+public boolean isEnabled() throws android.os.RemoteException;
+public int getState() 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;
+}
+)";
+
 const char kExpectedJavaOutputOutlining[] =
 R"(/*
  * This file is auto-generated.  DO NOT MODIFY.