dynamically generate host-side data object generator from the spec

Change-Id: I0eac7ec273c0e30ada47ce171e1bb9a5b58e9be3
diff --git a/sysfuzzer/common/proto/InterfaceSpecificationMessage.proto b/sysfuzzer/common/proto/InterfaceSpecificationMessage.proto
index c3599ee..dbe4a26 100644
--- a/sysfuzzer/common/proto/InterfaceSpecificationMessage.proto
+++ b/sysfuzzer/common/proto/InterfaceSpecificationMessage.proto
@@ -62,24 +62,13 @@
 }
 
 
-// A message for either primitive or aggregate data type.
-message DataType {
-  // Data type to describe the corresponding C/C++ data type.
-  optional bytes primitive_type = 1;
-  // Instance type to describe the semantic information.
-  optional bytes aggregate_type = 2;
-
-  optional PrimitiveDataValueMessage primitive_value = 11;
-}
-
-
 // To specify a function.
 message FunctionSpecificationMessage {
   // the function name.
   optional bytes name = 1;
 
   // data type of the return value (for legacy HALs and shared libraries).
-  optional DataType return_type = 11;
+  optional ArgumentSpecificationMessage return_type = 11;
 
   // data type of the return value (for HIDL HALs).
   repeated ArgumentSpecificationMessage return_type_hidl = 12;
@@ -99,17 +88,27 @@
   optional double double = 4;
   optional bytes bytes = 5;
   optional uint32 pointer = 6;
+
+  optional int32 int8_t = 7;
+  optional uint32 uint8_t = 8;
+  optional int32 char = 9;
+  optional int32 int16_t = 10;
+  optional uint32 uint16_t = 11;
+  optional int64 int64_t = 12;
+  optional uint64 uint64_t = 13;
+  optional bytes string = 14;
 }
 
 
 // To specify a function argument.
 message ArgumentSpecificationMessage {
   // Data type of the argument to describe the corresponding C/C++ data type.
-  optional bytes primitive_type = 1;
+  // only one is set if the argument is a primitive data.
+  repeated bytes primitive_type = 1;
   // Instance type of the argument to describe the semantic information.
-  optional bytes aggregate_type = 2;
+  repeated bytes aggregate_type = 2;
 
-  // true if the argument is an input.
+  // true if the argument is an input (valid only for the top-level message).
   optional bool is_input = 11 [default = true];
   // true if the argument is an output.
   optional bool is_output = 12 [default = false];
@@ -118,6 +117,11 @@
   repeated PrimitiveDataValueMessage primitive_value = 21;
   // the actual value(s) for an aggregated data type.
   repeated ArgumentSpecificationMessage aggregate_value = 22;
+
+  // the variable names of defined primitive type attributes.
+  repeated bytes primitive_name = 31;
+  // the variable names of defined aggregate type attributes.
+  repeated bytes aggregate_name = 32;
 }
 
 
@@ -136,4 +140,9 @@
 
   // a list of functions exposed by the component.
   repeated FunctionSpecificationMessage api = 2001;
+
+  // the names of custom-defined aggregate types.
+  repeated bytes aggregate_type_name = 3001;
+  // The actual definitions of custom-defined aggregate types.
+  repeated ArgumentSpecificationMessage aggregate_type_definition = 3002;
 }
diff --git a/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp b/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp
index f6d5e8e..b216115 100644
--- a/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp
+++ b/sysfuzzer/common/specification_parser/SpecificationBuilder.cpp
@@ -184,18 +184,20 @@
   void* result;
   cout << "Call Function " << func_msg->name() << endl;
   func_fuzzer->Fuzz(*func_msg, &result);
-  if (func_msg->return_type().has_aggregate_type()) {
+  if (func_msg->return_type().aggregate_type().size() > 0) {
+    // TODO: actually handle this case.
     if (result != NULL) {
       // loads that interface spec and enqueues all functions.
       cout << __FUNCTION__ << " return type: "
-          << func_msg->return_type().aggregate_type() << endl;
+          << func_msg->return_type().aggregate_type(0) << endl;
     } else {
       cout << __FUNCTION__ << " return value = NULL" << endl;
     }
     return *(new string("todo: support aggregate"));
-  } else if (func_msg->return_type().has_primitive_type()) {
-    if (!strcmp(func_msg->return_type().primitive_type().c_str(), "int32_t")) {
-      func_msg->mutable_return_type()->mutable_primitive_value()->set_int32_t(
+  } else if (func_msg->return_type().primitive_type().size() > 0) {
+    // TODO handle when the size > 1.
+    if (!strcmp(func_msg->return_type().primitive_type(0).c_str(), "int32_t")) {
+      func_msg->mutable_return_type()->mutable_primitive_value()->Add()->set_int32_t(
           *((int*)(&result)));
       cout << "result " << endl;
       // todo handle more types;
@@ -252,15 +254,16 @@
     void* result;
     cout << "Iteration " << (i + 1) << " Function " << func_msg->name() << endl;
     func_fuzzer->Fuzz(*func_msg, &result);
-    if (func_msg->return_type().has_aggregate_type()) {
+    if (func_msg->return_type().aggregate_type().size() > 0) {
       if (result != NULL) {
         // loads that interface spec and enqueues all functions.
         cout << __FUNCTION__ << " return type: "
-            << func_msg->return_type().aggregate_type() << endl;
-        string submodule_name = func_msg->return_type().aggregate_type();
+            << func_msg->return_type().aggregate_type(0) << endl;
+        // TODO: handle the case when size > 1
+        string submodule_name = func_msg->return_type().aggregate_type(0);
         while (!submodule_name.empty()
                && (std::isspace(submodule_name.back())
-                   || submodule_name.back() == '*' )) {
+                   || submodule_name.back() == '*')) {
           submodule_name.pop_back();
         }
         vts::InterfaceSpecificationMessage* iface_spec_msg =
diff --git a/sysfuzzer/libinterfacespecification/specification/LightHalV1.vts b/sysfuzzer/libinterfacespecification/specification/LightHalV1.vts
index 4f55d57..f8da026 100644
--- a/sysfuzzer/libinterfacespecification/specification/LightHalV1.vts
+++ b/sysfuzzer/libinterfacespecification/specification/LightHalV1.vts
@@ -21,3 +21,118 @@
     aggregate_type: "struct light_state_t*"
   }
 }
+
+aggregate_type_name: "light_state_t"
+aggregate_type_definition: {
+  primitive_type: "uint32_t"
+  primitive_name: "color"
+  primitive_value: {
+    uint32_t: 0xffffff00
+  }
+
+  primitive_type: "int32_t"
+  primitive_name: "flashMode"
+  primitive_value: {
+    int32_t: 0
+  }
+
+  primitive_type: "int32_t"
+  primitive_name: "flashOnMs"
+  primitive_value: {
+    int32_t: 0
+  }
+
+  primitive_type: "int32_t"
+  primitive_name: "flashOffMs"
+  primitive_value: {
+    int32_t: 0
+  }
+
+  primitive_type: "int32_t"
+  primitive_name: "brightnessMode"
+  primitive_value: {
+    int32_t: 0
+  }
+}
+
+
+aggregate_type_name: "const"
+aggregate_type_definition: {
+  primitive_type: "int32_t"
+  primitive_name: "LIGHT_FLASH_NONE"
+  primitive_value: {
+    int32_t: 0
+  }
+
+  primitive_type: "int32_t"
+  primitive_name: "LIGHT_FLASH_TIMED"
+  primitive_value: {
+    int32_t: 1
+  }
+
+  primitive_type: "int32_t"
+  primitive_name: "LIGHT_FLASH_HARDWARE"
+  primitive_value: {
+    int32_t: 2
+  }
+
+  primitive_type: "int32_t"
+  primitive_name: "BRIGHTNESS_MODE_USER"
+  primitive_value: {
+    int32_t: 0
+  }
+
+  primitive_type: "int32_t"
+  primitive_name: "BRIGHTNESS_MODE_SENSOR"
+  primitive_value: {
+    int32_t: 1
+  }
+
+  primitive_type: "bytes"
+  primitive_name: "LIGHT_ID_BACKLIGHT"
+  primitive_value: {
+    bytes: "backlight"
+  }
+
+  primitive_type: "bytes"
+  primitive_name: "LIGHT_ID_KEYBOARD"
+  primitive_value: {
+    bytes: "keyboard"
+  }
+
+  primitive_type: "bytes"
+  primitive_name: "LIGHT_ID_BUTTONS"
+  primitive_value: {
+    bytes: "buttons"
+  }
+
+  primitive_type: "bytes"
+  primitive_name: "LIGHT_ID_BATTERY"
+  primitive_value: {
+    bytes: "battery"
+  }
+
+  primitive_type: "bytes"
+  primitive_name: "LIGHT_ID_NOTIFICATIONS"
+  primitive_value: {
+    bytes: "notifications"
+  }
+
+  primitive_type: "bytes"
+  primitive_name: "LIGHT_ID_ATTENTION"
+  primitive_value: {
+    bytes: "attention"
+  }
+
+  primitive_type: "bytes"
+  primitive_name: "LIGHT_ID_BLUETOOTH"
+  primitive_value: {
+    bytes: "bluetooth"
+  }
+
+  primitive_type: "bytes"
+  primitive_name: "LIGHT_ID_WIFI"
+  primitive_value: {
+    bytes: "wifi"
+  }
+}
diff --git a/sysfuzzer/vtscompiler/VtsCompilerUtils.cpp b/sysfuzzer/vtscompiler/VtsCompilerUtils.cpp
index 02cc4e5..fc6142b 100644
--- a/sysfuzzer/vtscompiler/VtsCompilerUtils.cpp
+++ b/sysfuzzer/vtscompiler/VtsCompilerUtils.cpp
@@ -104,10 +104,15 @@
 
 
 string GetCppVariableType(ArgumentSpecificationMessage arg) {
-  if (arg.has_aggregate_type()) {
-    return arg.aggregate_type();
-  } else if (arg.has_primitive_type()) {
-    return GetCppVariableType(arg.primitive_type());
+  if (arg.aggregate_type().size() == 1) {
+    return arg.aggregate_type(0);
+  } else if (arg.primitive_type().size() == 1) {
+    return GetCppVariableType(arg.primitive_type(0));
+  } else if (arg.primitive_type().size() > 1
+             || arg.aggregate_type().size() > 1) {
+    cerr << __FUNCTION__
+        << ": aggregate type with multiple attributes; not supported" << endl;
+    exit(-1);
   }
   cerr << __FUNCTION__ << ": neither instance nor data type is set" << endl;
   exit(-1);
@@ -115,46 +120,54 @@
 
 
 string GetCppInstanceType(ArgumentSpecificationMessage arg, string msg) {
-  if (arg.has_aggregate_type()) {
-    if (!strcmp(arg.aggregate_type().c_str(), "struct light_state_t*")) {
+  if (arg.aggregate_type().size() == 1) {
+    if (!strcmp(arg.aggregate_type(0).c_str(), "struct light_state_t*")) {
       if (msg.length() == 0) {
         return "GenerateLightState()";
       } else {
         return "GenerateLightStateUsingMessage(" + msg + ")";
       }
-    } else if (!strcmp(arg.aggregate_type().c_str(), "GpsCallbacks*")) {
+    } else if (!strcmp(arg.aggregate_type(0).c_str(), "GpsCallbacks*")) {
       return "GenerateGpsCallbacks()";
-    } else if (!strcmp(arg.aggregate_type().c_str(), "GpsUtcTime")) {
+    } else if (!strcmp(arg.aggregate_type(0).c_str(), "GpsUtcTime")) {
       return "GenerateGpsUtcTime()";
-    } else if (!strcmp(arg.aggregate_type().c_str(), "vts_gps_latitude")) {
+    } else if (!strcmp(arg.aggregate_type(0).c_str(), "vts_gps_latitude")) {
       return "GenerateLatitude()";
-    } else if (!strcmp(arg.aggregate_type().c_str(), "vts_gps_longitude")) {
+    } else if (!strcmp(arg.aggregate_type(0).c_str(), "vts_gps_longitude")) {
       return "GenerateLongitude()";
-    } else if (!strcmp(arg.aggregate_type().c_str(), "vts_gps_accuracy")) {
+    } else if (!strcmp(arg.aggregate_type(0).c_str(), "vts_gps_accuracy")) {
       return "GenerateGpsAccuracy()";
-    } else if (!strcmp(arg.aggregate_type().c_str(), "vts_gps_flags_uint16")) {
+    } else if (!strcmp(arg.aggregate_type(0).c_str(), "vts_gps_flags_uint16")) {
       return "GenerateGpsFlagsUint16()";
-    } else if (!strcmp(arg.aggregate_type().c_str(), "GpsPositionMode")) {
+    } else if (!strcmp(arg.aggregate_type(0).c_str(), "GpsPositionMode")) {
       return "GenerateGpsPositionMode()";
-    } else if (!strcmp(arg.aggregate_type().c_str(), "GpsPositionRecurrence")) {
+    } else if (!strcmp(arg.aggregate_type(0).c_str(), "GpsPositionRecurrence")) {
       return "GenerateGpsPositionRecurrence()";
-    } else if (!strcmp(arg.aggregate_type().c_str(), "wifi_handle*")) {
+    } else if (!strcmp(arg.aggregate_type(0).c_str(), "wifi_handle*")) {
       return "(wifi_handle*) malloc(sizeof(wifi_handle))";
     } else {
       cerr << __FILE__ << ":" << __LINE__ << " "
-          << "unknown instance type " << arg.aggregate_type() << endl;
+          << "unknown instance type " << arg.aggregate_type(0) << endl;
     }
+  } else if (arg.aggregate_type().size() > 1) {
+    cerr << __FUNCTION__
+        << ": aggregate type with multiple attributes; not supported" << endl;
+    exit(-1);
   }
-  if (arg.has_primitive_type()) {
-    if (!strcmp(arg.primitive_type().c_str(), "uint32_t")) {
+  if (arg.primitive_type().size() > 1) {
+    cerr << __FUNCTION__
+        << ": a structure with multiple attributes; not supported" << endl;
+    exit(-1);
+  } else if (arg.primitive_type().size() == 1) {
+    if (!strcmp(arg.primitive_type(0).c_str(), "uint32_t")) {
       return "RandomUint32()";
-    } else if (!strcmp(arg.primitive_type().c_str(), "int32_t")) {
+    } else if (!strcmp(arg.primitive_type(0).c_str(), "int32_t")) {
       return "RandomInt32()";
-    } else if (!strcmp(arg.primitive_type().c_str(), "char_pointer")) {
+    } else if (!strcmp(arg.primitive_type(0).c_str(), "char_pointer")) {
       return "RandomCharPointer()";
     }
     cerr << __FILE__ << ":" << __LINE__ << " "
-        << "unknown data type " << arg.primitive_type() << endl;
+        << "unknown data type " << arg.primitive_type(0) << endl;
     exit(-1);
   }
   cerr << __FUNCTION__ << ": neither instance nor data type is set" << endl;
diff --git a/sysfuzzer/vtscompiler/code_gen/HalCodeGen.cpp b/sysfuzzer/vtscompiler/code_gen/HalCodeGen.cpp
index 955fc55..d351304 100644
--- a/sysfuzzer/vtscompiler/code_gen/HalCodeGen.cpp
+++ b/sysfuzzer/vtscompiler/code_gen/HalCodeGen.cpp
@@ -53,8 +53,8 @@
       cpp_ss << "    " << GetCppVariableType(arg) << " ";
       cpp_ss << "arg" << arg_count << " = ";
       if (arg_count == 0
-          && arg.has_aggregate_type()
-          && !strncmp(arg.aggregate_type().c_str(),
+          && arg.aggregate_type().size() == 1
+          && !strncmp(arg.aggregate_type(0).c_str(),
                       message.original_data_structure_name().c_str(),
                       message.original_data_structure_name().length())) {
         cpp_ss << "reinterpret_cast<" << GetCppVariableType(arg) << ">("
@@ -78,8 +78,8 @@
     // actual function call
     GenerateCodeToStartMeasurement(cpp_ss);
     cpp_ss << "    ";
-    if (api.return_type().has_primitive_type()
-        && !strcmp(api.return_type().primitive_type().c_str(), "void")) {
+    if (api.return_type().primitive_type().size() == 1
+        && !strcmp(api.return_type().primitive_type(0).c_str(), "void")) {
       cpp_ss << "*result = NULL;" << endl;
     } else {
       cpp_ss << "*result = const_cast<void*>(reinterpret_cast<const void*>(";
@@ -94,8 +94,9 @@
         cpp_ss << "," << endl;
       }
     }
-    if (!api.return_type().has_primitive_type()
-        || strcmp(api.return_type().primitive_type().c_str(), "void")) {
+    if (api.return_type().primitive_type().size() == 0
+        || (api.return_type().primitive_type().size() == 1
+            && strcmp(api.return_type().primitive_type(0).c_str(), "void"))) {
       cpp_ss << "))";
     }
     cpp_ss << ");" << endl;
diff --git a/sysfuzzer/vtscompiler/code_gen/LegacyHalCodeGen.cpp b/sysfuzzer/vtscompiler/code_gen/LegacyHalCodeGen.cpp
index 72310f2..146d4de 100644
--- a/sysfuzzer/vtscompiler/code_gen/LegacyHalCodeGen.cpp
+++ b/sysfuzzer/vtscompiler/code_gen/LegacyHalCodeGen.cpp
@@ -55,8 +55,8 @@
       cpp_ss << "    " << GetCppVariableType(arg) << " ";
       cpp_ss << "arg" << arg_count << " = ";
       if (arg_count == 0
-          && arg.has_aggregate_type()
-          && !strncmp(arg.aggregate_type().c_str(),
+          && arg.aggregate_type().size() == 1
+          && !strncmp(arg.aggregate_type(0).c_str(),
                       message.original_data_structure_name().c_str(),
                       message.original_data_structure_name().length())
           && message.original_data_structure_name().length() > 0) {
@@ -77,8 +77,8 @@
     cpp_ss << ");" << endl;
 
     // actual function call
-    if (api.return_type().has_primitive_type()
-        && !strcmp(api.return_type().primitive_type().c_str(), "void")) {
+    if (api.return_type().primitive_type().size() == 1
+        && !strcmp(api.return_type().primitive_type(0).c_str(), "void")) {
       cpp_ss << "*result = NULL;" << endl;
     } else {
       cpp_ss << "*result = const_cast<void*>(reinterpret_cast<const void*>(";
@@ -97,8 +97,9 @@
         cpp_ss << "," << endl;
       }
     }
-    if (!api.return_type().has_primitive_type()
-        || strcmp(api.return_type().primitive_type().c_str(), "void")) {
+    if (api.return_type().primitive_type().size() == 0
+        || (api.return_type().primitive_type().size() == 1
+            && strcmp(api.return_type().primitive_type(0).c_str(), "void"))) {
       cpp_ss << "))";
     }
     cpp_ss << ");" << endl;