support all nfc hidl hal apis

Change-Id: Ic01b75ffe20e980ca63d1c33a6acc60b204df73d
diff --git a/agents/hal/AgentRequestHandler.cpp b/agents/hal/AgentRequestHandler.cpp
index 4942ae4..c840a0e 100644
--- a/agents/hal/AgentRequestHandler.cpp
+++ b/agents/hal/AgentRequestHandler.cpp
@@ -285,6 +285,38 @@
   return VtsSocketSendMessage(response_msg);
 }
 
+bool AgentRequestHandler::ReadSpecification(const string& component_name) {
+  cout << "[runner->agent] command " << __FUNCTION__ << endl;
+#ifndef VTS_AGENT_DRIVER_COMM_BINDER  // socket
+  VtsDriverSocketClient* client = driver_client_;
+  if (!client) {
+#else  // binder
+  android::sp<android::vts::IVtsFuzzer> client =
+      android::vts::GetBinderClient(service_name_);
+  if (!client.get()) {
+#endif
+    return false;
+  }
+
+  const char* result = client->ReadSpecification(component_name);
+
+  AndroidSystemControlResponseMessage response_msg;
+  if (result != NULL && strlen(result) > 0) {
+    cout << "[agent] Call: success" << endl;
+    response_msg.set_response_code(SUCCESS);
+    response_msg.set_result(result);
+  } else {
+    cout << "[agent] Call: fail" << endl;
+    response_msg.set_response_code(FAIL);
+    response_msg.set_reason("Failed to call the api.");
+  }
+  bool succ = VtsSocketSendMessage(response_msg);
+#ifndef VTS_AGENT_DRIVER_COMM_BINDER  // socket
+  free((void*)result);
+#endif
+  return succ;
+}
+
 bool AgentRequestHandler::ListApis() {
   cout << "[runner->agent] command " << __FUNCTION__ << endl;
 // TODO: use an attribute (client) of a newly defined class.
@@ -475,6 +507,8 @@
           command_msg.file_path(), command_msg.target_class(),
           command_msg.target_type(), command_msg.target_version() / 100.0,
           command_msg.module_name(), command_msg.bits());
+    case VTS_AGENT_COMMAND_READ_SPECIFICATION:
+      return ReadSpecification(command_msg.service_name());
     case LIST_APIS:
       return ListApis();
     case CALL_API:
diff --git a/agents/hal/AgentRequestHandler.h b/agents/hal/AgentRequestHandler.h
index 699bc71..144c794 100644
--- a/agents/hal/AgentRequestHandler.h
+++ b/agents/hal/AgentRequestHandler.h
@@ -68,6 +68,9 @@
                            int target_type, float target_version,
                            const string& module_name, int bits);
 
+  // for the VTS_AGENT_COMMAND_READ_SPECIFICATION`
+  bool ReadSpecification(const string& component_name);
+
   // for the LIST_APIS command
   bool ListApis();
 
diff --git a/agents/hal/SocketClientToDriver.cpp b/agents/hal/SocketClientToDriver.cpp
index e3b08cc..e0cac13 100644
--- a/agents/hal/SocketClientToDriver.cpp
+++ b/agents/hal/SocketClientToDriver.cpp
@@ -104,6 +104,29 @@
   return result;
 }
 
+const char* VtsDriverSocketClient::ReadSpecification(
+    const string& component_name) {
+  cout << "[agent->driver] LIST_FUNCTIONS" << endl;
+
+  VtsDriverControlCommandMessage command_message;
+  command_message.set_command_type(
+      VTS_DRIVER_COMMAND_READ_SPECIFICATION);
+  command_message.set_module_name(component_name);
+  if (!VtsSocketSendMessage(command_message)) return NULL;
+
+  VtsDriverControlResponseMessage response_message;
+  if (!VtsSocketRecvMessage(&response_message)) return NULL;
+
+  char* result =
+      (char*)malloc(strlen(response_message.return_message().c_str()) + 1);
+  if (!result) {
+    cerr << __func__ << " ERROR result is NULL" << endl;
+    return NULL;
+  }
+  strcpy(result, response_message.return_message().c_str());
+  return result;
+}
+
 const char* VtsDriverSocketClient::Call(const string& arg) {
   VtsDriverControlCommandMessage command_message;
   command_message.set_command_type(CALL_FUNCTION);
diff --git a/agents/hal/SocketClientToDriver.h b/agents/hal/SocketClientToDriver.h
index 7ff1b12..dd1ac17 100644
--- a/agents/hal/SocketClientToDriver.h
+++ b/agents/hal/SocketClientToDriver.h
@@ -46,6 +46,10 @@
   // Sends a LIST_FUNCTIONS request.
   const char* GetFunctions();
 
+  // Sends a VTS_DRIVER_COMMAND_READ_SPECIFICATION request.
+  const char* ReadSpecification(
+          const string& component_name);
+
   // Sends a CALL_FUNCTION request.
   const char* Call(const string& arg);
 
diff --git a/proto/AndroidSystemControlMessage.proto b/proto/AndroidSystemControlMessage.proto
index afb00f7..2981107 100644
--- a/proto/AndroidSystemControlMessage.proto
+++ b/proto/AndroidSystemControlMessage.proto
@@ -33,6 +33,8 @@
   CHECK_DRIVER_SERVICE = 101;
   // To start a fuzzer binary service and select a HAL module.
   LAUNCH_DRIVER_SERVICE = 102;
+  // To read the VTS spec of a target component.
+  VTS_AGENT_COMMAND_READ_SPECIFICATION = 103;
 
   // To get a list of available functions.
   LIST_APIS = 201;
diff --git a/proto/AndroidSystemControlMessage_pb2.py b/proto/AndroidSystemControlMessage_pb2.py
index 795f7d9..ac61416 100644
--- a/proto/AndroidSystemControlMessage_pb2.py
+++ b/proto/AndroidSystemControlMessage_pb2.py
@@ -15,7 +15,7 @@
 DESCRIPTOR = _descriptor.FileDescriptor(
   name='AndroidSystemControlMessage.proto',
   package='android.vts',
-  serialized_pb='\n!AndroidSystemControlMessage.proto\x12\x0b\x61ndroid.vts\x1a#InterfaceSpecificationMessage.proto\"\xea\x02\n\"AndroidSystemControlCommandMessage\x12.\n\x0c\x63ommand_type\x18\x01 \x01(\x0e\x32\x18.android.vts.CommandType\x12\x0e\n\x05paths\x18\xe9\x07 \x03(\x0c\x12\x16\n\rcallback_port\x18\xcd\x08 \x01(\x05\x12\x15\n\x0cservice_name\x18\xd1\x0f \x01(\x0c\x12\x30\n\x0b\x64river_type\x18\xb9\x17 \x01(\x0e\x32\x1a.android.vts.VtsDriverType\x12\x12\n\tfile_path\x18\xba\x17 \x01(\x0c\x12\r\n\x04\x62its\x18\xbb\x17 \x01(\x05\x12\x15\n\x0ctarget_class\x18\xbc\x17 \x01(\x05\x12\x14\n\x0btarget_type\x18\xbd\x17 \x01(\x05\x12\x17\n\x0etarget_version\x18\xbe\x17 \x01(\x05\x12\x14\n\x0bmodule_name\x18\xbf\x17 \x01(\x0c\x12\x0c\n\x03\x61rg\x18\xa1\x1f \x01(\x0c\x12\x16\n\rshell_command\x18\x89\' \x03(\x0c\"\xd3\x01\n#AndroidSystemControlResponseMessage\x12\x30\n\rresponse_code\x18\x01 \x01(\x0e\x32\x19.android.vts.ResponseCode\x12\x0f\n\x06reason\x18\xe9\x07 \x01(\x0c\x12\x13\n\nfile_names\x18\xea\x07 \x03(\x0c\x12\r\n\x04spec\x18\xeb\x07 \x01(\x0c\x12\x0f\n\x06result\x18\xec\x07 \x01(\x0c\x12\x0f\n\x06stdout\x18\xd1\x0f \x03(\x0c\x12\x0f\n\x06stderr\x18\xd2\x0f \x03(\x0c\x12\x12\n\texit_code\x18\xd3\x0f \x03(\x05\"i\n#AndroidSystemCallbackRequestMessage\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x36\n\x03\x61rg\x18\x0b \x03(\x0b\x32).android.vts.VariableSpecificationMessage\"X\n$AndroidSystemCallbackResponseMessage\x12\x30\n\rresponse_code\x18\x01 \x01(\x0e\x32\x19.android.vts.ResponseCode*\xfb\x01\n\x0b\x43ommandType\x12\x18\n\x14UNKNOWN_COMMAND_TYPE\x10\x00\x12\r\n\tLIST_HALS\x10\x01\x12\x11\n\rSET_HOST_INFO\x10\x02\x12\x08\n\x04PING\x10\x03\x12\x18\n\x14\x43HECK_DRIVER_SERVICE\x10\x65\x12\x19\n\x15LAUNCH_DRIVER_SERVICE\x10\x66\x12\x0e\n\tLIST_APIS\x10\xc9\x01\x12\r\n\x08\x43\x41LL_API\x10\xca\x01\x12$\n\x1fVTS_AGENT_COMMAND_GET_ATTRIBUTE\x10\xcb\x01\x12,\n\'VTS_AGENT_COMMAND_EXECUTE_SHELL_COMMAND\x10\xad\x02*@\n\x0cResponseCode\x12\x19\n\x15UNKNOWN_RESPONSE_CODE\x10\x00\x12\x0b\n\x07SUCCESS\x10\x01\x12\x08\n\x04\x46\x41IL\x10\x02*\xfd\x01\n\rVtsDriverType\x12\x1a\n\x16UKNOWN_VTS_DRIVER_TYPE\x10\x00\x12$\n VTS_DRIVER_TYPE_HAL_CONVENTIONAL\x10\x01\x12\x1e\n\x1aVTS_DRIVER_TYPE_HAL_LEGACY\x10\x02\x12\x1c\n\x18VTS_DRIVER_TYPE_HAL_HIDL\x10\x03\x12\x31\n-VTS_DRIVER_TYPE_HAL_HIDL_WRAPPED_CONVENTIONAL\x10\x04\x12\x1e\n\x1aVTS_DRIVER_TYPE_LIB_SHARED\x10\x0b\x12\x19\n\x15VTS_DRIVER_TYPE_SHELL\x10\x15')
+  serialized_pb='\n!AndroidSystemControlMessage.proto\x12\x0b\x61ndroid.vts\x1a#InterfaceSpecificationMessage.proto\"\xea\x02\n\"AndroidSystemControlCommandMessage\x12.\n\x0c\x63ommand_type\x18\x01 \x01(\x0e\x32\x18.android.vts.CommandType\x12\x0e\n\x05paths\x18\xe9\x07 \x03(\x0c\x12\x16\n\rcallback_port\x18\xcd\x08 \x01(\x05\x12\x15\n\x0cservice_name\x18\xd1\x0f \x01(\x0c\x12\x30\n\x0b\x64river_type\x18\xb9\x17 \x01(\x0e\x32\x1a.android.vts.VtsDriverType\x12\x12\n\tfile_path\x18\xba\x17 \x01(\x0c\x12\r\n\x04\x62its\x18\xbb\x17 \x01(\x05\x12\x15\n\x0ctarget_class\x18\xbc\x17 \x01(\x05\x12\x14\n\x0btarget_type\x18\xbd\x17 \x01(\x05\x12\x17\n\x0etarget_version\x18\xbe\x17 \x01(\x05\x12\x14\n\x0bmodule_name\x18\xbf\x17 \x01(\x0c\x12\x0c\n\x03\x61rg\x18\xa1\x1f \x01(\x0c\x12\x16\n\rshell_command\x18\x89\' \x03(\x0c\"\xd3\x01\n#AndroidSystemControlResponseMessage\x12\x30\n\rresponse_code\x18\x01 \x01(\x0e\x32\x19.android.vts.ResponseCode\x12\x0f\n\x06reason\x18\xe9\x07 \x01(\x0c\x12\x13\n\nfile_names\x18\xea\x07 \x03(\x0c\x12\r\n\x04spec\x18\xeb\x07 \x01(\x0c\x12\x0f\n\x06result\x18\xec\x07 \x01(\x0c\x12\x0f\n\x06stdout\x18\xd1\x0f \x03(\x0c\x12\x0f\n\x06stderr\x18\xd2\x0f \x03(\x0c\x12\x12\n\texit_code\x18\xd3\x0f \x03(\x05\"i\n#AndroidSystemCallbackRequestMessage\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x36\n\x03\x61rg\x18\x0b \x03(\x0b\x32).android.vts.VariableSpecificationMessage\"X\n$AndroidSystemCallbackResponseMessage\x12\x30\n\rresponse_code\x18\x01 \x01(\x0e\x32\x19.android.vts.ResponseCode*\xa5\x02\n\x0b\x43ommandType\x12\x18\n\x14UNKNOWN_COMMAND_TYPE\x10\x00\x12\r\n\tLIST_HALS\x10\x01\x12\x11\n\rSET_HOST_INFO\x10\x02\x12\x08\n\x04PING\x10\x03\x12\x18\n\x14\x43HECK_DRIVER_SERVICE\x10\x65\x12\x19\n\x15LAUNCH_DRIVER_SERVICE\x10\x66\x12(\n$VTS_AGENT_COMMAND_READ_SPECIFICATION\x10g\x12\x0e\n\tLIST_APIS\x10\xc9\x01\x12\r\n\x08\x43\x41LL_API\x10\xca\x01\x12$\n\x1fVTS_AGENT_COMMAND_GET_ATTRIBUTE\x10\xcb\x01\x12,\n\'VTS_AGENT_COMMAND_EXECUTE_SHELL_COMMAND\x10\xad\x02*@\n\x0cResponseCode\x12\x19\n\x15UNKNOWN_RESPONSE_CODE\x10\x00\x12\x0b\n\x07SUCCESS\x10\x01\x12\x08\n\x04\x46\x41IL\x10\x02*\xfd\x01\n\rVtsDriverType\x12\x1a\n\x16UKNOWN_VTS_DRIVER_TYPE\x10\x00\x12$\n VTS_DRIVER_TYPE_HAL_CONVENTIONAL\x10\x01\x12\x1e\n\x1aVTS_DRIVER_TYPE_HAL_LEGACY\x10\x02\x12\x1c\n\x18VTS_DRIVER_TYPE_HAL_HIDL\x10\x03\x12\x31\n-VTS_DRIVER_TYPE_HAL_HIDL_WRAPPED_CONVENTIONAL\x10\x04\x12\x1e\n\x1aVTS_DRIVER_TYPE_LIB_SHARED\x10\x0b\x12\x19\n\x15VTS_DRIVER_TYPE_SHELL\x10\x15')
 
 _COMMANDTYPE = _descriptor.EnumDescriptor(
   name='CommandType',
@@ -48,26 +48,30 @@
       options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='LIST_APIS', index=6, number=201,
+      name='VTS_AGENT_COMMAND_READ_SPECIFICATION', index=6, number=103,
       options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='CALL_API', index=7, number=202,
+      name='LIST_APIS', index=7, number=201,
       options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='VTS_AGENT_COMMAND_GET_ATTRIBUTE', index=8, number=203,
+      name='CALL_API', index=8, number=202,
       options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='VTS_AGENT_COMMAND_EXECUTE_SHELL_COMMAND', index=9, number=301,
+      name='VTS_AGENT_COMMAND_GET_ATTRIBUTE', index=9, number=203,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='VTS_AGENT_COMMAND_EXECUTE_SHELL_COMMAND', index=10, number=301,
       options=None,
       type=None),
   ],
   containing_type=None,
   options=None,
   serialized_start=864,
-  serialized_end=1115,
+  serialized_end=1157,
 )
 
 CommandType = enum_type_wrapper.EnumTypeWrapper(_COMMANDTYPE)
@@ -92,8 +96,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=1117,
-  serialized_end=1181,
+  serialized_start=1159,
+  serialized_end=1223,
 )
 
 ResponseCode = enum_type_wrapper.EnumTypeWrapper(_RESPONSECODE)
@@ -134,8 +138,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=1184,
-  serialized_end=1437,
+  serialized_start=1226,
+  serialized_end=1479,
 )
 
 VtsDriverType = enum_type_wrapper.EnumTypeWrapper(_VTSDRIVERTYPE)
@@ -145,6 +149,7 @@
 PING = 3
 CHECK_DRIVER_SERVICE = 101
 LAUNCH_DRIVER_SERVICE = 102
+VTS_AGENT_COMMAND_READ_SPECIFICATION = 103
 LIST_APIS = 201
 CALL_API = 202
 VTS_AGENT_COMMAND_GET_ATTRIBUTE = 203
diff --git a/proto/InterfaceSpecificationMessage.proto b/proto/InterfaceSpecificationMessage.proto
index 7617055..7800e4c 100644
--- a/proto/InterfaceSpecificationMessage.proto
+++ b/proto/InterfaceSpecificationMessage.proto
@@ -129,6 +129,12 @@
   // a specification of the call flows of the function.
   repeated CallFlowSpecificationMessage callflow = 31;
 
+  // whether it is a callback.
+  optional bool is_callback = 41;
+
+  // when it is a callback.
+  optional FunctionPointerSpecificationMessage function_pointer = 42;
+
   // profiling data.
   repeated float profiling_data = 101;
 
diff --git a/proto/InterfaceSpecificationMessage_pb2.py b/proto/InterfaceSpecificationMessage_pb2.py
index b16d0d3..0dbd68f 100644
--- a/proto/InterfaceSpecificationMessage_pb2.py
+++ b/proto/InterfaceSpecificationMessage_pb2.py
@@ -14,7 +14,7 @@
 DESCRIPTOR = _descriptor.FileDescriptor(
   name='InterfaceSpecificationMessage.proto',
   package='android.vts',
-  serialized_pb='\n#InterfaceSpecificationMessage.proto\x12\x0b\x61ndroid.vts\"e\n\x1c\x43\x61llFlowSpecificationMessage\x12\x14\n\x05\x65ntry\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04\x65xit\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x0c\n\x04next\x18\x0b \x03(\x0c\x12\x0c\n\x04prev\x18\x0c \x03(\x0c\"C\n NativeCodeCoverageRawDataMessage\x12\x11\n\tfile_path\x18\x01 \x01(\x0c\x12\x0c\n\x04gcda\x18\x0b \x01(\x0c\"\xa9\x04\n\x1c\x46unctionSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x16\n\x0esubmodule_name\x18\x02 \x01(\x0c\x12>\n\x0breturn_type\x18\x0b \x01(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x43\n\x10return_type_hidl\x18\x0c \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12N\n\x1areturn_type_submodule_spec\x18\r \x01(\x0b\x32*.android.vts.InterfaceSpecificationMessage\x12\x36\n\x03\x61rg\x18\x15 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12;\n\x08\x63\x61llflow\x18\x1f \x03(\x0b\x32).android.vts.CallFlowSpecificationMessage\x12\x16\n\x0eprofiling_data\x18\x65 \x03(\x02\x12 \n\x17processed_coverage_data\x18\xc9\x01 \x03(\r\x12I\n\x11raw_coverage_data\x18\xca\x01 \x03(\x0b\x32-.android.vts.NativeCodeCoverageRawDataMessage\x12\x14\n\x0bparent_path\x18\xad\x02 \x01(\x0c\"\x84\x03\n\x16ScalarDataValueMessage\x12\x0e\n\x06\x62ool_t\x18\x01 \x01(\x05\x12\x0e\n\x06int8_t\x18\x0b \x01(\x05\x12\x0f\n\x07uint8_t\x18\x0c \x01(\r\x12\x0c\n\x04\x63har\x18\r \x01(\x05\x12\r\n\x05uchar\x18\x0e \x01(\r\x12\x0f\n\x07int16_t\x18\x15 \x01(\x05\x12\x10\n\x08uint16_t\x18\x16 \x01(\r\x12\x0f\n\x07int32_t\x18\x1f \x01(\x05\x12\x10\n\x08uint32_t\x18  \x01(\r\x12\x0f\n\x07int64_t\x18) \x01(\x03\x12\x10\n\x08uint64_t\x18* \x01(\x04\x12\x0f\n\x07\x66loat_t\x18\x65 \x01(\x02\x12\x10\n\x08\x64ouble_t\x18\x66 \x01(\x01\x12\x10\n\x07pointer\x18\xc9\x01 \x01(\r\x12\x0f\n\x06opaque\x18\xca\x01 \x01(\r\x12\x15\n\x0cvoid_pointer\x18\xd3\x01 \x01(\r\x12\x15\n\x0c\x63har_pointer\x18\xd4\x01 \x01(\r\x12\x16\n\ruchar_pointer\x18\xd5\x01 \x01(\r\x12\x18\n\x0fpointer_pointer\x18\xfb\x01 \x01(\r\x12\r\n\x04\x62its\x18\xe9\x07 \x01(\r\"\xee\x01\n\x16VectorDataValueMessage\x12\'\n\x04type\x18\x01 \x01(\x0e\x32\x19.android.vts.VariableType\x12\x0c\n\x04size\x18\x02 \x01(\r\x12\x13\n\x0bscalar_type\x18\x0b \x01(\x0c\x12\x32\n\x05value\x18\x0c \x03(\x0b\x32#.android.vts.ScalarDataValueMessage\x12\x13\n\x0bstruct_type\x18\x15 \x01(\x0c\x12?\n\x0cstruct_value\x18\x16 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\"\xd1\x01\n#FunctionPointerSpecificationMessage\x12\x15\n\rfunction_name\x18\x01 \x01(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x0b \x01(\r\x12\n\n\x02id\x18\x15 \x01(\x0c\x12\x36\n\x03\x61rg\x18\x65 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12>\n\x0breturn_type\x18o \x01(\x0b\x32).android.vts.VariableSpecificationMessage\"9\n\x16StringDataValueMessage\x12\x0f\n\x07message\x18\x01 \x01(\x0c\x12\x0e\n\x06length\x18\x0b \x01(\r\"9\n\x14\x45numDataValueMessage\x12\x12\n\nenumerator\x18\x01 \x03(\x0c\x12\r\n\x05value\x18\x02 \x03(\r\"\xee\x05\n\x1cVariableSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\'\n\x04type\x18\x02 \x01(\x0e\x32\x19.android.vts.VariableType\x12\x11\n\tused_bits\x18\x0b \x01(\x05\x12\x39\n\x0cscalar_value\x18\x65 \x01(\x0b\x32#.android.vts.ScalarDataValueMessage\x12\x13\n\x0bscalar_type\x18\x66 \x01(\x0c\x12\x39\n\x0cstring_value\x18o \x01(\x0b\x32#.android.vts.StringDataValueMessage\x12\x35\n\nenum_value\x18y \x01(\x0b\x32!.android.vts.EnumDataValueMessage\x12:\n\x0cvector_value\x18\x83\x01 \x03(\x0b\x32#.android.vts.VectorDataValueMessage\x12@\n\x0cstruct_value\x18\x8d\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x14\n\x0bstruct_type\x18\x8e\x01 \x01(\x0c\x12?\n\x0bunion_value\x18\x97\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x18\n\x0fpredefined_type\x18\xc9\x01 \x01(\x0c\x12K\n\x10\x66unction_pointer\x18\xdd\x01 \x03(\x0b\x32\x30.android.vts.FunctionPointerSpecificationMessage\x12\x1b\n\x12hidl_callback_type\x18\xe7\x01 \x01(\x0c\x12\x17\n\x08is_input\x18\xad\x02 \x01(\x08:\x04true\x12\x19\n\tis_output\x18\xae\x02 \x01(\x08:\x05\x66\x61lse\x12\x18\n\x08is_const\x18\xaf\x02 \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0bis_callback\x18\xb0\x02 \x01(\x08:\x05\x66\x61lse\"\xfb\x01\n\x1aStructSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x19\n\nis_pointer\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x37\n\x03\x61pi\x18\xe9\x07 \x03(\x0b\x32).android.vts.FunctionSpecificationMessage\x12<\n\nsub_struct\x18\xd1\x0f \x03(\x0b\x32\'.android.vts.StructSpecificationMessage\x12=\n\tattribute\x18\xb9\x17 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\"\xd3\x03\n\x1dInterfaceSpecificationMessage\x12\x34\n\x0f\x63omponent_class\x18\x01 \x01(\x0e\x32\x1b.android.vts.ComponentClass\x12\x32\n\x0e\x63omponent_type\x18\x02 \x01(\x0e\x32\x1a.android.vts.ComponentType\x12!\n\x16\x63omponent_type_version\x18\x03 \x01(\x02:\x01\x31\x12\x16\n\x0e\x63omponent_name\x18\x04 \x01(\x0c\x12\x0f\n\x07package\x18\x0b \x01(\x0c\x12\x0e\n\x06import\x18\x0c \x03(\x0c\x12%\n\x1coriginal_data_structure_name\x18\xe9\x07 \x01(\x0c\x12\x0f\n\x06header\x18\xea\x07 \x03(\x0c\x12\x37\n\x03\x61pi\x18\xd1\x0f \x03(\x0b\x32).android.vts.FunctionSpecificationMessage\x12=\n\tattribute\x18\xb9\x17 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12<\n\nsub_struct\x18\xa1\x1f \x03(\x0b\x32\'.android.vts.StructSpecificationMessage*\xaa\x01\n\x0e\x43omponentClass\x12\x11\n\rUNKNOWN_CLASS\x10\x00\x12\x14\n\x10HAL_CONVENTIONAL\x10\x01\x12\x1e\n\x1aHAL_CONVENTIONAL_SUBMODULE\x10\x02\x12\x0e\n\nHAL_LEGACY\x10\x03\x12\x0c\n\x08HAL_HIDL\x10\x04\x12!\n\x1dHAL_HIDL_WRAPPED_CONVENTIONAL\x10\x05\x12\x0e\n\nLIB_SHARED\x10\x0b*\xa1\x01\n\rComponentType\x12\x10\n\x0cUNKNOWN_TYPE\x10\x00\x12\t\n\x05\x41UDIO\x10\x01\x12\n\n\x06\x43\x41MERA\x10\x02\x12\x07\n\x03GPS\x10\x03\x12\t\n\x05LIGHT\x10\x04\x12\x08\n\x04WIFI\x10\x05\x12\n\n\x06MOBILE\x10\x06\x12\r\n\tBLUETOOTH\x10\x07\x12\x07\n\x03NFC\x10\x08\x12\x10\n\x0b\x42IONIC_LIBM\x10\xe9\x07\x12\x13\n\x0eVNDK_LIBCUTILS\x10\xcd\x08*\xf7\x01\n\x0cVariableType\x12\x19\n\x15UNKNOWN_VARIABLE_TYPE\x10\x00\x12\x13\n\x0fTYPE_PREDEFINED\x10\x01\x12\x0f\n\x0bTYPE_SCALAR\x10\x02\x12\x0f\n\x0bTYPE_STRING\x10\x03\x12\r\n\tTYPE_ENUM\x10\x04\x12\x0e\n\nTYPE_ARRAY\x10\x05\x12\x0f\n\x0bTYPE_VECTOR\x10\x06\x12\x0f\n\x0bTYPE_STRUCT\x10\x07\x12\x19\n\x15TYPE_FUNCTION_POINTER\x10\x08\x12\r\n\tTYPE_VOID\x10\t\x12\x16\n\x12TYPE_HIDL_CALLBACK\x10\n\x12\x12\n\x0eTYPE_SUBMODULE\x10\x0b')
+  serialized_pb='\n#InterfaceSpecificationMessage.proto\x12\x0b\x61ndroid.vts\"e\n\x1c\x43\x61llFlowSpecificationMessage\x12\x14\n\x05\x65ntry\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04\x65xit\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x0c\n\x04next\x18\x0b \x03(\x0c\x12\x0c\n\x04prev\x18\x0c \x03(\x0c\"C\n NativeCodeCoverageRawDataMessage\x12\x11\n\tfile_path\x18\x01 \x01(\x0c\x12\x0c\n\x04gcda\x18\x0b \x01(\x0c\"\x8a\x05\n\x1c\x46unctionSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x16\n\x0esubmodule_name\x18\x02 \x01(\x0c\x12>\n\x0breturn_type\x18\x0b \x01(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x43\n\x10return_type_hidl\x18\x0c \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12N\n\x1areturn_type_submodule_spec\x18\r \x01(\x0b\x32*.android.vts.InterfaceSpecificationMessage\x12\x36\n\x03\x61rg\x18\x15 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12;\n\x08\x63\x61llflow\x18\x1f \x03(\x0b\x32).android.vts.CallFlowSpecificationMessage\x12\x13\n\x0bis_callback\x18) \x01(\x08\x12J\n\x10\x66unction_pointer\x18* \x01(\x0b\x32\x30.android.vts.FunctionPointerSpecificationMessage\x12\x16\n\x0eprofiling_data\x18\x65 \x03(\x02\x12 \n\x17processed_coverage_data\x18\xc9\x01 \x03(\r\x12I\n\x11raw_coverage_data\x18\xca\x01 \x03(\x0b\x32-.android.vts.NativeCodeCoverageRawDataMessage\x12\x14\n\x0bparent_path\x18\xad\x02 \x01(\x0c\"\x84\x03\n\x16ScalarDataValueMessage\x12\x0e\n\x06\x62ool_t\x18\x01 \x01(\x05\x12\x0e\n\x06int8_t\x18\x0b \x01(\x05\x12\x0f\n\x07uint8_t\x18\x0c \x01(\r\x12\x0c\n\x04\x63har\x18\r \x01(\x05\x12\r\n\x05uchar\x18\x0e \x01(\r\x12\x0f\n\x07int16_t\x18\x15 \x01(\x05\x12\x10\n\x08uint16_t\x18\x16 \x01(\r\x12\x0f\n\x07int32_t\x18\x1f \x01(\x05\x12\x10\n\x08uint32_t\x18  \x01(\r\x12\x0f\n\x07int64_t\x18) \x01(\x03\x12\x10\n\x08uint64_t\x18* \x01(\x04\x12\x0f\n\x07\x66loat_t\x18\x65 \x01(\x02\x12\x10\n\x08\x64ouble_t\x18\x66 \x01(\x01\x12\x10\n\x07pointer\x18\xc9\x01 \x01(\r\x12\x0f\n\x06opaque\x18\xca\x01 \x01(\r\x12\x15\n\x0cvoid_pointer\x18\xd3\x01 \x01(\r\x12\x15\n\x0c\x63har_pointer\x18\xd4\x01 \x01(\r\x12\x16\n\ruchar_pointer\x18\xd5\x01 \x01(\r\x12\x18\n\x0fpointer_pointer\x18\xfb\x01 \x01(\r\x12\r\n\x04\x62its\x18\xe9\x07 \x01(\r\"\xee\x01\n\x16VectorDataValueMessage\x12\'\n\x04type\x18\x01 \x01(\x0e\x32\x19.android.vts.VariableType\x12\x0c\n\x04size\x18\x02 \x01(\r\x12\x13\n\x0bscalar_type\x18\x0b \x01(\x0c\x12\x32\n\x05value\x18\x0c \x03(\x0b\x32#.android.vts.ScalarDataValueMessage\x12\x13\n\x0bstruct_type\x18\x15 \x01(\x0c\x12?\n\x0cstruct_value\x18\x16 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\"\xd1\x01\n#FunctionPointerSpecificationMessage\x12\x15\n\rfunction_name\x18\x01 \x01(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x0b \x01(\r\x12\n\n\x02id\x18\x15 \x01(\x0c\x12\x36\n\x03\x61rg\x18\x65 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12>\n\x0breturn_type\x18o \x01(\x0b\x32).android.vts.VariableSpecificationMessage\"9\n\x16StringDataValueMessage\x12\x0f\n\x07message\x18\x01 \x01(\x0c\x12\x0e\n\x06length\x18\x0b \x01(\r\"9\n\x14\x45numDataValueMessage\x12\x12\n\nenumerator\x18\x01 \x03(\x0c\x12\r\n\x05value\x18\x02 \x03(\r\"\xee\x05\n\x1cVariableSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\'\n\x04type\x18\x02 \x01(\x0e\x32\x19.android.vts.VariableType\x12\x11\n\tused_bits\x18\x0b \x01(\x05\x12\x39\n\x0cscalar_value\x18\x65 \x01(\x0b\x32#.android.vts.ScalarDataValueMessage\x12\x13\n\x0bscalar_type\x18\x66 \x01(\x0c\x12\x39\n\x0cstring_value\x18o \x01(\x0b\x32#.android.vts.StringDataValueMessage\x12\x35\n\nenum_value\x18y \x01(\x0b\x32!.android.vts.EnumDataValueMessage\x12:\n\x0cvector_value\x18\x83\x01 \x03(\x0b\x32#.android.vts.VectorDataValueMessage\x12@\n\x0cstruct_value\x18\x8d\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x14\n\x0bstruct_type\x18\x8e\x01 \x01(\x0c\x12?\n\x0bunion_value\x18\x97\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x18\n\x0fpredefined_type\x18\xc9\x01 \x01(\x0c\x12K\n\x10\x66unction_pointer\x18\xdd\x01 \x03(\x0b\x32\x30.android.vts.FunctionPointerSpecificationMessage\x12\x1b\n\x12hidl_callback_type\x18\xe7\x01 \x01(\x0c\x12\x17\n\x08is_input\x18\xad\x02 \x01(\x08:\x04true\x12\x19\n\tis_output\x18\xae\x02 \x01(\x08:\x05\x66\x61lse\x12\x18\n\x08is_const\x18\xaf\x02 \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0bis_callback\x18\xb0\x02 \x01(\x08:\x05\x66\x61lse\"\xfb\x01\n\x1aStructSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x19\n\nis_pointer\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x37\n\x03\x61pi\x18\xe9\x07 \x03(\x0b\x32).android.vts.FunctionSpecificationMessage\x12<\n\nsub_struct\x18\xd1\x0f \x03(\x0b\x32\'.android.vts.StructSpecificationMessage\x12=\n\tattribute\x18\xb9\x17 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\"\xd3\x03\n\x1dInterfaceSpecificationMessage\x12\x34\n\x0f\x63omponent_class\x18\x01 \x01(\x0e\x32\x1b.android.vts.ComponentClass\x12\x32\n\x0e\x63omponent_type\x18\x02 \x01(\x0e\x32\x1a.android.vts.ComponentType\x12!\n\x16\x63omponent_type_version\x18\x03 \x01(\x02:\x01\x31\x12\x16\n\x0e\x63omponent_name\x18\x04 \x01(\x0c\x12\x0f\n\x07package\x18\x0b \x01(\x0c\x12\x0e\n\x06import\x18\x0c \x03(\x0c\x12%\n\x1coriginal_data_structure_name\x18\xe9\x07 \x01(\x0c\x12\x0f\n\x06header\x18\xea\x07 \x03(\x0c\x12\x37\n\x03\x61pi\x18\xd1\x0f \x03(\x0b\x32).android.vts.FunctionSpecificationMessage\x12=\n\tattribute\x18\xb9\x17 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12<\n\nsub_struct\x18\xa1\x1f \x03(\x0b\x32\'.android.vts.StructSpecificationMessage*\xaa\x01\n\x0e\x43omponentClass\x12\x11\n\rUNKNOWN_CLASS\x10\x00\x12\x14\n\x10HAL_CONVENTIONAL\x10\x01\x12\x1e\n\x1aHAL_CONVENTIONAL_SUBMODULE\x10\x02\x12\x0e\n\nHAL_LEGACY\x10\x03\x12\x0c\n\x08HAL_HIDL\x10\x04\x12!\n\x1dHAL_HIDL_WRAPPED_CONVENTIONAL\x10\x05\x12\x0e\n\nLIB_SHARED\x10\x0b*\xa1\x01\n\rComponentType\x12\x10\n\x0cUNKNOWN_TYPE\x10\x00\x12\t\n\x05\x41UDIO\x10\x01\x12\n\n\x06\x43\x41MERA\x10\x02\x12\x07\n\x03GPS\x10\x03\x12\t\n\x05LIGHT\x10\x04\x12\x08\n\x04WIFI\x10\x05\x12\n\n\x06MOBILE\x10\x06\x12\r\n\tBLUETOOTH\x10\x07\x12\x07\n\x03NFC\x10\x08\x12\x10\n\x0b\x42IONIC_LIBM\x10\xe9\x07\x12\x13\n\x0eVNDK_LIBCUTILS\x10\xcd\x08*\xf7\x01\n\x0cVariableType\x12\x19\n\x15UNKNOWN_VARIABLE_TYPE\x10\x00\x12\x13\n\x0fTYPE_PREDEFINED\x10\x01\x12\x0f\n\x0bTYPE_SCALAR\x10\x02\x12\x0f\n\x0bTYPE_STRING\x10\x03\x12\r\n\tTYPE_ENUM\x10\x04\x12\x0e\n\nTYPE_ARRAY\x10\x05\x12\x0f\n\x0bTYPE_VECTOR\x10\x06\x12\x0f\n\x0bTYPE_STRUCT\x10\x07\x12\x19\n\x15TYPE_FUNCTION_POINTER\x10\x08\x12\r\n\tTYPE_VOID\x10\t\x12\x16\n\x12TYPE_HIDL_CALLBACK\x10\n\x12\x12\n\x0eTYPE_SUBMODULE\x10\x0b')
 
 _COMPONENTCLASS = _descriptor.EnumDescriptor(
   name='ComponentClass',
@@ -53,8 +53,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=3220,
-  serialized_end=3390,
+  serialized_start=3317,
+  serialized_end=3487,
 )
 
 ComponentClass = enum_type_wrapper.EnumTypeWrapper(_COMPONENTCLASS)
@@ -111,8 +111,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=3393,
-  serialized_end=3554,
+  serialized_start=3490,
+  serialized_end=3651,
 )
 
 ComponentType = enum_type_wrapper.EnumTypeWrapper(_COMPONENTTYPE)
@@ -173,8 +173,8 @@
   ],
   containing_type=None,
   options=None,
-  serialized_start=3557,
-  serialized_end=3804,
+  serialized_start=3654,
+  serialized_end=3901,
 )
 
 VariableType = enum_type_wrapper.EnumTypeWrapper(_VARIABLETYPE)
@@ -352,28 +352,42 @@
       is_extension=False, extension_scope=None,
       options=None),
     _descriptor.FieldDescriptor(
-      name='profiling_data', full_name='android.vts.FunctionSpecificationMessage.profiling_data', index=7,
+      name='is_callback', full_name='android.vts.FunctionSpecificationMessage.is_callback', index=7,
+      number=41, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='function_pointer', full_name='android.vts.FunctionSpecificationMessage.function_pointer', index=8,
+      number=42, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='profiling_data', full_name='android.vts.FunctionSpecificationMessage.profiling_data', index=9,
       number=101, type=2, cpp_type=6, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     _descriptor.FieldDescriptor(
-      name='processed_coverage_data', full_name='android.vts.FunctionSpecificationMessage.processed_coverage_data', index=8,
+      name='processed_coverage_data', full_name='android.vts.FunctionSpecificationMessage.processed_coverage_data', index=10,
       number=201, type=13, cpp_type=3, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     _descriptor.FieldDescriptor(
-      name='raw_coverage_data', full_name='android.vts.FunctionSpecificationMessage.raw_coverage_data', index=9,
+      name='raw_coverage_data', full_name='android.vts.FunctionSpecificationMessage.raw_coverage_data', index=11,
       number=202, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       options=None),
     _descriptor.FieldDescriptor(
-      name='parent_path', full_name='android.vts.FunctionSpecificationMessage.parent_path', index=10,
+      name='parent_path', full_name='android.vts.FunctionSpecificationMessage.parent_path', index=12,
       number=301, type=12, cpp_type=9, label=1,
       has_default_value=False, default_value="",
       message_type=None, enum_type=None, containing_type=None,
@@ -389,7 +403,7 @@
   is_extendable=False,
   extension_ranges=[],
   serialized_start=225,
-  serialized_end=778,
+  serialized_end=875,
 )
 
 
@@ -549,8 +563,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=781,
-  serialized_end=1169,
+  serialized_start=878,
+  serialized_end=1266,
 )
 
 
@@ -612,8 +626,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=1172,
-  serialized_end=1410,
+  serialized_start=1269,
+  serialized_end=1507,
 )
 
 
@@ -668,8 +682,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=1413,
-  serialized_end=1622,
+  serialized_start=1510,
+  serialized_end=1719,
 )
 
 
@@ -703,8 +717,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=1624,
-  serialized_end=1681,
+  serialized_start=1721,
+  serialized_end=1778,
 )
 
 
@@ -738,8 +752,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=1683,
-  serialized_end=1740,
+  serialized_start=1780,
+  serialized_end=1837,
 )
 
 
@@ -885,8 +899,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=1743,
-  serialized_end=2493,
+  serialized_start=1840,
+  serialized_end=2590,
 )
 
 
@@ -941,8 +955,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=2496,
-  serialized_end=2747,
+  serialized_start=2593,
+  serialized_end=2844,
 )
 
 
@@ -1039,8 +1053,8 @@
   options=None,
   is_extendable=False,
   extension_ranges=[],
-  serialized_start=2750,
-  serialized_end=3217,
+  serialized_start=2847,
+  serialized_end=3314,
 )
 
 _FUNCTIONSPECIFICATIONMESSAGE.fields_by_name['return_type'].message_type = _VARIABLESPECIFICATIONMESSAGE
@@ -1048,6 +1062,7 @@
 _FUNCTIONSPECIFICATIONMESSAGE.fields_by_name['return_type_submodule_spec'].message_type = _INTERFACESPECIFICATIONMESSAGE
 _FUNCTIONSPECIFICATIONMESSAGE.fields_by_name['arg'].message_type = _VARIABLESPECIFICATIONMESSAGE
 _FUNCTIONSPECIFICATIONMESSAGE.fields_by_name['callflow'].message_type = _CALLFLOWSPECIFICATIONMESSAGE
+_FUNCTIONSPECIFICATIONMESSAGE.fields_by_name['function_pointer'].message_type = _FUNCTIONPOINTERSPECIFICATIONMESSAGE
 _FUNCTIONSPECIFICATIONMESSAGE.fields_by_name['raw_coverage_data'].message_type = _NATIVECODECOVERAGERAWDATAMESSAGE
 _VECTORDATAVALUEMESSAGE.fields_by_name['type'].enum_type = _VARIABLETYPE
 _VECTORDATAVALUEMESSAGE.fields_by_name['value'].message_type = _SCALARDATAVALUEMESSAGE
diff --git a/proto/VtsDriverControlMessage.proto b/proto/VtsDriverControlMessage.proto
index ccae7ca..b5db7e3 100644
--- a/proto/VtsDriverControlMessage.proto
+++ b/proto/VtsDriverControlMessage.proto
@@ -35,6 +35,8 @@
   CALL_FUNCTION = 103;
   // To get the value of an attribute.
   GET_ATTRIBUTE = 104;
+  // To read the specification message of a component.
+  VTS_DRIVER_COMMAND_READ_SPECIFICATION = 105;
 
   // for a shell driver
   // To execute a shell command.
diff --git a/runners/host/tcp_client/vts_tcp_client.py b/runners/host/tcp_client/vts_tcp_client.py
index d917bde..c198a4a 100755
--- a/runners/host/tcp_client/vts_tcp_client.py
+++ b/runners/host/tcp_client/vts_tcp_client.py
@@ -39,6 +39,7 @@
                      2: "SET_HOST_INFO",
                      101: "CHECK_DRIVER_SERVICE",
                      102: "LAUNCH_DRIVER_SERVICE",
+                     103: "VTS_AGENT_COMMAND_READ_SPECIFICATION",
                      201: "LIST_APIS",
                      202: "CALL_API",
                      203: "VTS_AGENT_COMMAND_GET_ATTRIBUTE",
@@ -245,6 +246,27 @@
             return True
         return False
 
+    def ReadSpecification(self, interface_name):
+        """RPC to VTS_AGENT_COMMAND_READ_SPECIFICATION."""
+        self.SendCommand(
+            SysMsg_pb2.VTS_AGENT_COMMAND_READ_SPECIFICATION,
+            service_name=interface_name)
+        resp = self.RecvResponse(retries=2)
+        logging.info("resp for VTS_AGENT_COMMAND_EXECUTE_READ_INTERFACE: %s",
+                     resp)
+        logging.info("proto: %s",
+                     resp.result)
+        result = IfaceSpecMsg_pb2.InterfaceSpecificationMessage()
+        if resp.result == "error":
+            raise errors.VtsTcpCommunicationError(
+                "API call error by the VTS driver.")
+        try:
+            text_format.Merge(resp.result, result)
+        except text_format.ParseError as e:
+            logging.exception(e)
+            logging.error("Paring error\n%s", resp.result)
+        return result
+
     def SendCommand(self,
                     command_type,
                     paths=None,
diff --git a/setup.sh b/setup.sh
index e64a251..ba14a3a 100755
--- a/setup.sh
+++ b/setup.sh
@@ -61,6 +61,7 @@
   adb push specification/hal_conventional/BluetoothHalV1bt_interface_t.vts /data/local/tmp/spec/BluetoothHalV1bt_interface_t.vts
   adb push specification/hal_hidl/Nfc.vts /data/local/tmp/spec/Nfc.vts
   adb push specification/hal_hidl/NfcClientCallback.vts /data/local/tmp/spec/NfcClientCallback.vts
+  adb push specification/hal_hidl/types.vts /data/local/tmp/spec/types.vts
   adb push specification/lib_bionic/libmV1.vts /data/local/tmp/spec/libmV1.vts
   adb push specification/lib_bionic/libcutilsV1.vts /data/local/tmp/spec/libcutilsV1.vts
 
diff --git a/specification/hal_hidl/Nfc.vts b/specification/hal_hidl/Nfc.vts
index 0d57aef..90fc71d 100644
--- a/specification/hal_hidl/Nfc.vts
+++ b/specification/hal_hidl/Nfc.vts
@@ -16,6 +16,7 @@
   arg: {
     type: TYPE_HIDL_CALLBACK
     predefined_type: "INfcClientCallback"
+    is_callback: true
   }
 }
 
diff --git a/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp b/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp
index a917058..3b549a3 100644
--- a/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp
+++ b/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp
@@ -81,6 +81,35 @@
   return NULL;
 }
 
+vts::InterfaceSpecificationMessage*
+SpecificationBuilder::FindInterfaceSpecification(const string& component_name) {
+  DIR* dir;
+  struct dirent* ent;
+
+  if (!(dir = opendir(dir_path_.c_str()))) {
+    cerr << __FUNCTION__ << ": Can't opendir " << dir_path_ << endl;
+    return NULL;
+  }
+
+  while ((ent = readdir(dir))) {
+    if (string(ent->d_name).find(SPEC_FILE_EXT) != std::string::npos) {
+      cout << __FUNCTION__ << ": Checking a file " << ent->d_name << endl;
+      const string file_path = string(dir_path_) + "/" + string(ent->d_name);
+      vts::InterfaceSpecificationMessage* message =
+          new vts::InterfaceSpecificationMessage();
+      if (InterfaceSpecificationParser::parse(file_path.c_str(), message)) {
+        if (message->component_name() == component_name) {
+          closedir(dir);
+          return message;
+        }
+      }
+      delete message;
+    }
+  }
+  closedir(dir);
+  return NULL;
+}
+
 FuzzerBase* SpecificationBuilder::GetFuzzerBase(
     const vts::InterfaceSpecificationMessage& iface_spec_msg,
     const char* dll_file_name, const char* target_func_name) {
diff --git a/sysfuzzer/common/specification_parser/SpecificationBuilder.h b/sysfuzzer/common/specification_parser/SpecificationBuilder.h
index 1dc80be..7b16c43 100644
--- a/sysfuzzer/common/specification_parser/SpecificationBuilder.h
+++ b/sysfuzzer/common/specification_parser/SpecificationBuilder.h
@@ -50,6 +50,9 @@
       const int target_class, const int target_type, const float target_version,
       const string submodule_name = "");
 
+  vts::InterfaceSpecificationMessage*
+      FindInterfaceSpecification(const string& component_name);
+
   // Returns FuzzBase for a given interface specification, and adds all the
   // found functions to the fuzzing job queue.
   FuzzerBase* GetFuzzerBaseAndAddAllFunctionsToQueue(
diff --git a/sysfuzzer/framework/SocketServer.cpp b/sysfuzzer/framework/SocketServer.cpp
index d36c3a8..5be3372 100644
--- a/sysfuzzer/framework/SocketServer.cpp
+++ b/sysfuzzer/framework/SocketServer.cpp
@@ -80,6 +80,14 @@
   return 0;
 }
 
+const char* VtsDriverHalSocketServer::ReadSpecification(const string& name) {
+  printf("VtsFuzzerServer::ReadSpecification(%s)\n", name.c_str());
+  InterfaceSpecificationMessage* msg = spec_builder_.FindInterfaceSpecification(name);
+  string* result = new string();
+  google::protobuf::TextFormat::PrintToString(*msg, result);
+  return result->c_str();
+}
+
 const char* VtsDriverHalSocketServer::Call(const string& arg) {
   printf("VtsFuzzerServer::Call(%s)\n", arg.c_str());
   FunctionSpecificationMessage* func_msg = new FunctionSpecificationMessage();
@@ -158,6 +166,14 @@
       if (VtsSocketSendMessage(response_message)) return true;
       break;
     }
+    case VTS_DRIVER_COMMAND_READ_SPECIFICATION: {
+      const char* result = ReadSpecification(command_message.module_name());
+      VtsDriverControlResponseMessage response_message;
+      response_message.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS);
+      response_message.set_return_message(result);
+      if (VtsSocketSendMessage(response_message)) return true;
+      break;
+    }
     case GET_ATTRIBUTE: {
       const char* result = GetAttribute(command_message.arg());
       VtsDriverControlResponseMessage response_message;
diff --git a/sysfuzzer/framework/SocketServer.h b/sysfuzzer/framework/SocketServer.h
index dfea532..560a017 100644
--- a/sysfuzzer/framework/SocketServer.h
+++ b/sysfuzzer/framework/SocketServer.h
@@ -40,6 +40,7 @@
   int32_t LoadHal(const string& path, int target_class, int target_type,
                   float target_version, const string& module_name);
   int32_t Status(int32_t type);
+  const char* ReadSpecification(const string& name);
   const char* Call(const string& arg);
   const char* GetAttribute(const string& arg);
   const char* GetFunctions();
diff --git a/sysfuzzer/vtscompiler/code_gen/CodeGenBase.cpp b/sysfuzzer/vtscompiler/code_gen/CodeGenBase.cpp
index 16a17da..82a7dda 100644
--- a/sysfuzzer/vtscompiler/code_gen/CodeGenBase.cpp
+++ b/sysfuzzer/vtscompiler/code_gen/CodeGenBase.cpp
@@ -105,6 +105,12 @@
         cpp_ss << "#include <" << package_path << "/"
                << GetVersionString(message.component_type_version())
                << "/Bn" << base_filename.substr(1) << ".h>" << endl;
+        if (base_filename.substr(0, 1) == "I") {
+          cpp_ss << "#include \""
+                 << input_vfs_file_path.substr(0, input_vfs_file_path.find_last_of("\\/"))
+                 << "/" << base_filename.substr(1, base_filename.find_last_of(".h"))
+                 << ".vts.h\"" << endl;
+        }
       }
       cpp_ss << "#include <" << package_path << "/"
              << GetVersionString(message.component_type_version())
@@ -173,7 +179,7 @@
     }
 
     cpp_ss << "Vts" << message.component_name().substr(1) << "* VtsFuzzerCreate"
-           << message.component_name() << "()";
+           << message.component_name() << "(const string& callback_socket_name)";
     cpp_ss << " {" << endl
            << "  return new Vts" << message.component_name().substr(1) << "();"
            << endl;
@@ -295,7 +301,7 @@
     h_ss << endl;
 
     h_ss << "Vts" << message.component_name().substr(1) << "* VtsFuzzerCreate"
-       << message.component_name() << "();" << endl;
+       << message.component_name() << "(const string& callback_socket_name);" << endl;
     h_ss << endl;
   }
 
@@ -372,6 +378,11 @@
       if (attribute.type() == TYPE_ENUM) {
         h_ss << attribute.name() << " " << "Random" << attribute.name() << "();"
                << endl;
+      } else if (attribute.type() == TYPE_STRUCT) {
+        h_ss << "void " << "MessageTo" << attribute.name()
+             << "(const VariableSpecificationMessage& var_msg, "
+             << attribute.name() << "* arg);"
+             << endl;
       }
     }
   }
diff --git a/sysfuzzer/vtscompiler/code_gen/HalHidlCodeGen.cpp b/sysfuzzer/vtscompiler/code_gen/HalHidlCodeGen.cpp
index 35aec60..d196aee 100644
--- a/sysfuzzer/vtscompiler/code_gen/HalHidlCodeGen.cpp
+++ b/sysfuzzer/vtscompiler/code_gen/HalHidlCodeGen.cpp
@@ -218,7 +218,8 @@
       if (!arg.is_callback() && arg.type() == TYPE_HIDL_CALLBACK &&
           callbacks.find(arg.predefined_type()) == callbacks.end()) {
         cpp_ss << "extern " << arg.predefined_type() << "* "
-               << "VtsFuzzerCreate" << arg.predefined_type() << "();" << endl << endl;
+               << "VtsFuzzerCreate" << arg.predefined_type()
+               << "(const string& callback_socket_name);" << endl << endl;
         callbacks.insert(arg.predefined_type());
       }
     }
@@ -276,65 +277,75 @@
       int arg_count = 0;
       for (auto const& arg : api.arg()) {
         if (arg.is_callback()) {  // arg.type() isn't always TYPE_FUNCTION_POINTER
-          string name = "vts_callback_" + fuzzer_extended_class_name + "_" +
-                        arg.predefined_type();  // TODO - check to make sure name
-                                                // is always correct
-          if (name.back() == '*') name.pop_back();
-          cpp_ss << "    " << name << "* arg" << arg_count << "callback = new ";
-          cpp_ss << name << "(callback_socket_name);" << endl;
-          cpp_ss << "    arg" << arg_count << "callback->Register(func_msg->arg("
-                 << arg_count << "));" << endl;
+          if (arg.type() == TYPE_PREDEFINED) {
+            string name = "vts_callback_" + fuzzer_extended_class_name + "_" +
+                arg.predefined_type();  // TODO - check to make sure name
+                                        // is always correct
+            if (name.back() == '*') name.pop_back();
+            cpp_ss << "    " << name << "* arg" << arg_count << "callback = new ";
+            cpp_ss << name << "(callback_socket_name);" << endl;
+            cpp_ss << "    arg" << arg_count << "callback->Register(func_msg->arg("
+                   << arg_count << "));" << endl;
 
-          cpp_ss << "    " << GetCppVariableType(arg, &message) << " ";
-          cpp_ss << "arg" << arg_count << " = (" << GetCppVariableType(arg, &message)
-                 << ") malloc(sizeof(" << GetCppVariableType(arg, &message) << "));"
-                 << endl;
-          // TODO: think about how to free the malloced callback data structure.
-          // find the spec.
-          bool found = false;
-          cout << name << endl;
-          for (auto const& attribute : message.attribute()) {
-            if (attribute.type() == TYPE_FUNCTION_POINTER &&
-                attribute.is_callback()) {
-              string target_name = "vts_callback_" + fuzzer_extended_class_name +
-                                   "_" + attribute.name();
-              cout << "compare" << endl;
-              cout << target_name << endl;
-              if (name == target_name) {
-                if (attribute.function_pointer_size() > 1) {
-                  for (auto const& func_pt : attribute.function_pointer()) {
-                    cpp_ss << "    arg" << arg_count << "->"
-                           << func_pt.function_name() << " = arg" << arg_count
-                           << "callback->" << func_pt.function_name() << ";"
-                           << endl;
+            cpp_ss << "    " << GetCppVariableType(arg, &message) << " ";
+            cpp_ss << "arg" << arg_count << " = (" << GetCppVariableType(arg, &message)
+                   << ") malloc(sizeof(" << GetCppVariableType(arg, &message) << "));"
+                   << endl;
+            // TODO: think about how to free the malloced callback data structure.
+            // find the spec.
+            bool found = false;
+            cout << name << endl;
+            for (auto const& attribute : message.attribute()) {
+              if (attribute.type() == TYPE_FUNCTION_POINTER &&
+                  attribute.is_callback()) {
+                string target_name = "vts_callback_" + fuzzer_extended_class_name +
+                                     "_" + attribute.name();
+                cout << "compare" << endl;
+                cout << target_name << endl;
+                if (name == target_name) {
+                  if (attribute.function_pointer_size() > 1) {
+                    for (auto const& func_pt : attribute.function_pointer()) {
+                      cpp_ss << "    arg" << arg_count << "->"
+                             << func_pt.function_name() << " = arg" << arg_count
+                             << "callback->" << func_pt.function_name() << ";"
+                             << endl;
+                    }
+                  } else {
+                    cpp_ss << "    arg" << arg_count << " = arg" << arg_count
+                           << "callback->" << attribute.name() << ";" << endl;
                   }
-                } else {
-                  cpp_ss << "    arg" << arg_count << " = arg" << arg_count
-                         << "callback->" << attribute.name() << ";" << endl;
+                  found = true;
+                  break;
                 }
-                found = true;
-                break;
               }
             }
-          }
-          if (!found) {
-            cerr << __func__ << " ERROR callback definition missing for " << name
-                 << " of " << api.name() << endl;
-            exit(-1);
+            if (!found) {
+              cerr << __func__ << " ERROR callback definition missing for " << name
+                   << " of " << api.name() << endl;
+              exit(-1);
+            }
+          } else if (arg.type() == TYPE_HIDL_CALLBACK) {
+            cpp_ss << "    sp<" << arg.predefined_type()  << "> arg" << arg_count
+                   << "(" << "VtsFuzzerCreate"
+                   << arg.predefined_type() << "(callback_socket_name));" << endl;
           }
         } else {
           if (arg.type() == TYPE_VECTOR) {
             cpp_ss << "    " << arg.vector_value(0).scalar_type() << "* "
                    << "arg" << arg_count << "buffer = ("
                    << arg.vector_value(0).scalar_type()
-                   << "*) malloc(8 * sizeof("
+                   << "*) malloc("
+                   << "func_msg->arg(" << arg_count
+                   << ").vector_value(0).value().size()"
+                   << " * sizeof("
                    << arg.vector_value(0).scalar_type() << "));"
                    << endl;
           }
+
           if (arg.type() == TYPE_HIDL_CALLBACK) {
             cpp_ss << "    sp<" << arg.predefined_type()  << "> arg" << arg_count
                    << "(" << "VtsFuzzerCreate"
-                   << arg.predefined_type() << "());" << endl;
+                   << arg.predefined_type() << "(callback_socket_name));" << endl;
           } else if (arg.type() == TYPE_STRUCT) {
             cpp_ss << "    " << GetCppVariableType(arg, &message) << " ";
             cpp_ss << "arg" << arg_count;
@@ -389,8 +400,6 @@
               cpp_ss << ") : ";
             } else if (arg.type() == TYPE_ENUM) {
               // TODO: impl
-            } else if (arg.type() == TYPE_STRUCT) {
-              // TODO: impl
             } else {
               cerr << __func__ << ":" << __LINE__ << " unknown type "
                    << arg.type() << endl;
@@ -406,10 +415,26 @@
             // a message to a C/C++ struct.
           } else if (arg.type() == TYPE_VECTOR) {
             // TODO: dynamically generate the initial value for hidl_vec
+            cpp_ss << "    for (int vector_index = 0; vector_index < "
+                   << "func_msg->arg(" << arg_count << ").vector_value(0).value().size(); "
+                   << "vector_index++) {" << endl;
+            cpp_ss << "      arg" << arg_count << "buffer[vector_index] = "
+                   << "func_msg->arg(" << arg_count << ").vector_value(0).value(vector_index)."
+                   << arg.vector_value(0).scalar_type() << "();"
+                   << endl;
+            cpp_ss << "    }" << endl;
             cpp_ss << "arg" << arg_count << ".setTo("
-                   << "arg" << arg_count << "buffer, 8)";
+                   << "arg" << arg_count << "buffer, "
+                   << "func_msg->arg(" << arg_count << ").vector_value(0).value().size()"
+                   << ")";
           }
           cpp_ss << ";" << endl;
+          if (arg.type() == TYPE_STRUCT) {
+            if (message.component_class() == HAL_HIDL) {
+              cpp_ss << "    MessageTo" << GetCppVariableType(arg, &message)
+                     << "(func_msg->arg(" << arg_count << "), &arg" << arg_count << ");" << endl;
+            }
+          }
         }
         arg_count++;
       }
@@ -477,8 +502,39 @@
                << attribute.enum_value().enumerator(0)
                << ";" << endl;
         cpp_ss << "}" << endl;
+      } else if (attribute.type() == TYPE_STRUCT) {
+        cpp_ss << "void " << "MessageTo" << attribute.name()
+               << "(const VariableSpecificationMessage& var_msg, "
+               << attribute.name() << "* arg) {"
+               << endl;
+        int struct_index = 0;
+        for (const auto& struct_value : attribute.struct_value()) {
+          if (struct_value.type() == TYPE_VECTOR) {
+            cpp_ss << "  arg->" << struct_value.name() << ".resize("
+                   << "var_msg.struct_value(" << struct_index
+                   << ").vector_value(0).value().size()"
+                   << ");" << endl;
+            cpp_ss << "  for (int value_index = 0; value_index < "
+                   << "var_msg.struct_value(" << struct_index
+                   << ").vector_value(0).value().size(); "
+                   << "value_index++) {" << endl;
+            cpp_ss << "    arg->" << struct_value.name() << "[value_index] = "
+                   << "var_msg.struct_value(" << struct_index
+                   << ").vector_value(0).value(value_index)."
+                   << struct_value.vector_value(0).scalar_type() << "();"
+                   << endl;
+            cpp_ss << "  }" << endl;
+          } else {
+            cerr << __func__ << ":" << __LINE__ << " ERROR unsupported type "
+                 << struct_value.type() << endl;
+            exit(-1);
+          }
+          struct_index++;
+        }
+        cpp_ss << "}" << endl;
       } else {
-        cerr << __func__ << " unsupported attribute type" << endl;
+        cerr << __func__ << " unsupported attribute type "
+             << attribute.type() << endl;
       }
     }
   }
diff --git a/testcases/host/nfc/hidl/NfcHidlBasicTest.py b/testcases/host/nfc/hidl/NfcHidlBasicTest.py
index ff5b060..05238fc 100644
--- a/testcases/host/nfc/hidl/NfcHidlBasicTest.py
+++ b/testcases/host/nfc/hidl/NfcHidlBasicTest.py
@@ -16,6 +16,7 @@
 #
 
 import logging
+import time
 
 from vts.runners.host import base_test_with_webdb
 from vts.runners.host import test_runner
@@ -33,19 +34,57 @@
                                  bits=64)
 
     def testBase(self):
-        """A simple testcase which just calls a function."""
-        # TODO: extend to make realistic testcases
-        result = self.dut.hal.nfc.open()
-        logging.info("result: %s", result.return_type.string_value.message)
+        """A simple testcase which just calls each registered function."""
 
-    def TestNormla(self):
-        """A simple testcase which just calls functions."""
-        result = self.dut.hal.nfc.open()
-        logging.info("result: %s", result.return_type.string_value.message)
-        result = self.dut.hal.nfc.core_initialized(0)
-        logging.info("result: %s", result.return_type.string_value.message)
+        # TODO: extend to make realistic testcases
+        def send_event(nfc_event_t, nfc_status_t):
+            logging.info("callback send_event")
+            logging.info("arg0 %s", nfc_event_t)
+            logging.info("arg1 %s", nfc_status_t)
+
+        def send_data(nfc_data_t):
+            logging.info("callback send_data")
+            logging.info("arg0 %s", nfc_data_t)
+
+        client_callback = self.dut.hal.nfc.GetHidlCallbackInterface(
+            "INfcClientCallback",
+            sendEvent=send_event,
+            sendData=send_data)
+
+        result = self.dut.hal.nfc.open(client_callback)
+        logging.info("open result: %s",
+                     result.return_type.string_value.message)
+
+        result = self.dut.hal.nfc.pre_discover()
+        logging.info("pre_discover result: %s",
+                     result.return_type.string_value.message)
+
+        result = self.dut.hal.nfc.control_granted()
+        logging.info("control_granted result: %s",
+                     result.return_type.string_value.message)
+
+        result = self.dut.hal.nfc.power_cycle()
+        logging.info("power_cycle result: %s",
+                     result.return_type.string_value.message)
+
+        result = self.dut.hal.nfc.core_initialized([0, 9, 8])
+        logging.info("core_initialized result: %s",
+                     result.return_type.string_value.message)
+
+        nfc_types = self.dut.hal.nfc.GetHidlTypeInterface("types")
+        logging.info("nfc_types: %s", nfc_types)
+        data_vec = nfc_types.nfc_data_t(data=[0, 1, 2, 3, 4, 5])
+        logging.info("data_vec: %s", data_vec)
+
+        result = self.dut.hal.nfc.write(data_vec)
+        logging.info("write result: %s",
+                     result.return_type.string_value.message)
+
         result = self.dut.hal.nfc.close()
-        logging.info("result: %s", result.return_type.string_value.message)
+        logging.info("close result: %s",
+                     result.return_type.string_value.message)
+
+        time.sleep(5)
 
 
 if __name__ == "__main__":
diff --git a/utils/python/mirror/mirror_object.py b/utils/python/mirror/mirror_object.py
index e0d51be..28ba1d1 100644
--- a/utils/python/mirror/mirror_object.py
+++ b/utils/python/mirror/mirror_object.py
@@ -20,6 +20,7 @@
 import random
 
 from vts.utils.python.fuzzer import FuzzerUtils
+from vts.utils.python.mirror import mirror_object_for_types
 from vts.proto import InterfaceSpecificationMessage_pb2 as IfaceSpecMsg
 from google.protobuf import text_format
 
@@ -132,6 +133,28 @@
             return RemoteCallToGetAttribute()
         raise MirrorObjectError("unknown attribute name %s" % attribute_name)
 
+    def GetHidlCallbackInterface(self, interface_name, **kwargs):
+        result = self._client.ReadSpecification(interface_name)
+        logging.info("result %s", result)
+
+        var_msg = IfaceSpecMsg.VariableSpecificationMessage()
+        var_msg.name = interface_name
+        var_msg.type = IfaceSpecMsg.TYPE_FUNCTION_POINTER
+        for given_name, given_value in kwargs.iteritems():
+            for api in result.api:
+                logging.debug("check %s %s", api.name, given_name)
+                if given_name == api.name:
+                    func_pt_msg = var_msg.function_pointer.add()
+                    func_pt_msg.function_name = given_name
+                    func_pt_msg.id = self.GetFunctionPointerID(given_value)
+                    break
+        return var_msg
+
+    def GetHidlTypeInterface(self, interface_name):
+        result = self._client.ReadSpecification(interface_name)
+        logging.info("result %s", result)
+        return mirror_object_for_types.MirrorObjectForTypes(result)
+
     def CleanUp(self):
         self._client.Disconnect()
 
@@ -260,6 +283,18 @@
                             arg_msg.type = IfaceSpecMsg.TYPE_SCALAR
                             arg_msg.scalar_value.float_t = value_msg
                             arg_msg.scalar_type = "float_t"
+                        elif isinstance(value_msg, list):
+                            if arg_msg.type == IfaceSpecMsg.TYPE_VECTOR:
+                                arg_msg.vector_value[0].scalar_type
+                                for value in value_msg:
+                                    scalar_value = arg_msg.vector_value[0].value.add()
+                                    setattr(
+                                        scalar_value,
+                                        arg_msg.vector_value[0].scalar_type,
+                                        value)
+                            else:
+                                raise MirrorObjectError(
+                                    "unsupported type %s" % arg_msg.type)
                         else:
                             # TODO: check in advance (whether it's a message)
                             if isinstance(
@@ -291,6 +326,10 @@
                                         logging.error("TYPE_STRUCT unsupported")
                                     elif value.type == IfaceSpecMsg.TYPE_FUNCTION_POINTER:
                                         logging.error("TYPE_FUNCTION_POINTER unsupported")
+                                    elif value.type == IfaceSpecMsg.TYPE_VECTOR:
+                                        logging.info("copy before arg %s", arg)
+                                        logging.info("copy before value %s", value)
+                                        # skip
                                     else:
                                         raise MirrorObjectError(
                                             "unsupport type %s" % value.type)
diff --git a/utils/python/mirror/mirror_object_for_types.py b/utils/python/mirror/mirror_object_for_types.py
new file mode 100644
index 0000000..63ed142
--- /dev/null
+++ b/utils/python/mirror/mirror_object_for_types.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 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.
+#
+
+import copy
+import logging
+import random
+
+from vts.utils.python.fuzzer import FuzzerUtils
+from vts.proto import InterfaceSpecificationMessage_pb2 as IfaceSpecMsg
+from google.protobuf import text_format
+
+
+class MirrorObjectError(Exception):
+    """Raised when there is a general error in manipulating a mirror object."""
+    pass
+
+
+class MirrorObjectForTypes(object):
+    """The class that can create host-side mirroed variable instances.
+
+    Attributes:
+        _if_spec_msg: the interface specification message of a host object to
+                      mirror.
+        _parent_path: the name of a sub struct this object mirrors.
+    """
+
+    def __init__(self, msg, parent_path=None):
+        self._if_spec_msg = msg
+        self._parent_path = parent_path
+
+    def GetSubStruct(self, sub_struct_name):
+        """Returns the Struct Specification Message.
+
+        Args:
+            sub_struct_name: string, the name of the target sub struct attribute.
+
+        Returns:
+            StructSpecificationMessage if found, None otherwise
+        """
+        if self._if_spec_msg.sub_struct:
+            for sub_struct in self._if_spec_msg.sub_struct:
+                if sub_struct.name == sub_struct_name:
+                    return copy.copy(sub_struct)
+        return None
+
+    def GetCustomAggregateType(self, type_name):
+        """Returns the Argument Specification Message.
+
+        Args:
+            type_name: string, the name of the target data type.
+
+        Returns:
+            VariableSpecificationMessage if found, None otherwise
+        """
+        try:
+            for attribute in self._if_spec_msg.attribute:
+                if not attribute.is_const and attribute.name == type_name:
+                    return copy.copy(attribute)
+            return None
+        except AttributeError as e:
+            # TODO: check in advance whether self._if_spec_msg Interface
+            # SpecificationMessage.
+            return None
+
+    def GetConstType(self, type_name):
+        """Returns the Argument Specification Message.
+
+        Args:
+            type_name: string, the name of the target const data variable.
+
+        Returns:
+            VariableSpecificationMessage if found, None otherwise
+        """
+        try:
+            for attribute in self._if_spec_msg.attribute:
+                if attribute.is_const and attribute.name == type_name:
+                    return copy.copy(attribute)
+                elif attribute.type == IfaceSpecMsg.TYPE_ENUM:
+                    for enumerator, value in zip(attribute.enum_value.enumerator,
+                                                 attribute.enum_value.value):
+                        if enumerator == type_name:
+                          return copy.copy(attribute)
+            return None
+        except AttributeError as e:
+            # TODO: check in advance whether self._if_spec_msg Interface
+            # SpecificationMessage.
+            return None
+
+    # TODO: Guard against calls to this function after self.CleanUp is called.
+    def __getattr__(self, api_name, *args, **kwargs):
+        """Calls a target component's API.
+
+        Args:
+            api_name: string, the name of an API function to call.
+            *args: a list of arguments
+            **kwargs: a dict for the arg name and value pairs
+        """
+        def MessageGenerator(*args, **kwargs):
+            """Dynamically generates a custom message instance."""
+            arg_msg = self.GetCustomAggregateType(api_name)
+            if not arg_msg:
+                raise MirrorObjectError("arg %s unknown" % arg_msg)
+            logging.info("MessageGenerator %s %s", api_name, arg_msg)
+            logging.debug("MESSAGE %s", api_name)
+            if arg_msg.type == IfaceSpecMsg.TYPE_STRUCT:
+                for struct_value in arg_msg.struct_value:
+                    logging.debug("for %s %s",
+                                  struct_value.name, struct_value.scalar_type)
+                    first_vector_elem = True
+                    for given_name, given_value in kwargs.iteritems():
+                        logging.debug("check %s %s", struct_value.name, given_name)
+                        if given_name == struct_value.name:
+                            logging.debug("match type=%s", struct_value.scalar_type)
+                            if struct_value.type == IfaceSpecMsg.TYPE_SCALAR:
+                                if struct_value.scalar_type == "uint32_t":
+                                    struct_value.scalar_value.uint32_t = given_value
+                                elif struct_value.scalar_type == "int32_t":
+                                    struct_value.scalar_value.int32_t = given_value
+                                else:
+                                    raise MirrorObjectError(
+                                        "support %s" % struct_value.scalar_type)
+                            elif struct_value.type == IfaceSpecMsg.TYPE_VECTOR:
+                                sclar_type = struct_value.vector_value[0].scalar_type
+                                for value in given_value:
+                                    vector_value = struct_value.vector_value[0].value.add()
+                                    setattr(vector_value, sclar_type, value)
+                            continue
+            elif arg_msg.type == IfaceSpecMsg.TYPE_FUNCTION_POINTER:
+                for fp_value in arg_msg.function_pointer:
+                    logging.debug("for %s", fp_value.function_name)
+                    for given_name, given_value in kwargs.iteritems():
+                          logging.debug("check %s %s", fp_value.function_name, given_name)
+                          if given_name == fp_value.function_name:
+                              fp_value.id = self.GetFunctionPointerID(given_value)
+                              break
+
+            if arg_msg.type == IfaceSpecMsg.TYPE_STRUCT:
+                for struct_value, given_value in zip(arg_msg.struct_value, args):
+                    logging.debug("arg match type=%s", struct_value.scalar_type)
+                    if struct_value.type == IfaceSpecMsg.TYPE_SCALAR:
+                        if struct_value.scalar_type == "uint32_t":
+                            struct_value.scalar_value.uint32_t = given_value
+                        elif struct_value.scalar_type == "int32_t":
+                            struct_value.scalar_value.int32_t = given_value
+                        else:
+                            raise MirrorObjectError("support %s" % p_type)
+            elif arg_msg.type == IfaceSpecMsg.TYPE_FUNCTION_POINTER:
+                for fp_value, given_value in zip(arg_msg.function_pointer, args):
+                    logging.debug("for %s", fp_value.function_name)
+                    fp_value.id = self.GetFunctionPointerID(given_value)
+                    logging.debug("fp %s", fp_value)
+            logging.debug("generated %s", arg_msg)
+            return arg_msg
+
+        def ConstGenerator():
+            """Dynamically generates a const variable's value."""
+            arg_msg = self.GetConstType(api_name)
+            if not arg_msg:
+                raise MirrorObjectError("const %s unknown" % arg_msg)
+            logging.debug("check %s", api_name)
+            if arg_msg.type == IfaceSpecMsg.TYPE_SCALAR:
+                ret_v = getattr(arg_msg.scalar_value, arg_msg.scalar_type, None)
+                if ret_v is None:
+                    raise MirrorObjectError(
+                        "No value found for type %s in %s." % (p_type, value))
+                return ret_v
+            elif arg_msg.type == IfaceSpecMsg.TYPE_STRING:
+                return arg_msg.string_value.message
+            elif arg_msg.type == IfaceSpecMsg.TYPE_ENUM:
+                for enumerator, value in zip(arg_msg.enum_value.enumerator,
+                                             arg_msg.enum_value.value):
+                    if enumerator == api_name:
+                      return value
+            raise MirrorObjectError("const %s not found" % api_name)
+
+        struct_msg = self.GetSubStruct(api_name)
+        if struct_msg:
+            logging.debug("sub_struct %s", struct_msg)
+            if self._parent_path:
+                parent_name = "%s.%s" % (self._parent_path, api_name)
+            else:
+                parent_name = api_name
+            return MirrorObjectForTypes(struct_msg, parent_path=parent_name)
+
+        # handle attributes.
+        arg_msg = self.GetCustomAggregateType(api_name)
+        if arg_msg:
+            logging.debug("arg %s", arg_msg)
+            return MessageGenerator
+
+        arg_msg = self.GetConstType(api_name)
+        if arg_msg:
+            logging.debug("const %s *\n%s", api_name, arg_msg)
+            return ConstGenerator()
+
+        raise MirrorObjectError("unknown api name %s" % api_name)