1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef TOOLS_TELEMETRY_LUA_INTERPRETER_LUA_ENGINE_H_
18 #define TOOLS_TELEMETRY_LUA_INTERPRETER_LUA_ENGINE_H_
19 
20 #include <string>
21 #include <vector>
22 
23 #include "lua.hpp"
24 
25 namespace lua_interpreter {
26 
27 // Encapsulates Lua script execution environment.
28 // Example:
29 //      LuaEngine lua_engine;
30 //      std::vector<std::string> script_output =
31 //          lua_engine.ExecuteScript("print('2')")
32 class LuaEngine {
33  public:
34   // Creates a new instance of the LuaEngine.
35   LuaEngine();
36   ~LuaEngine();
37 
38   // Loads Lua script provided as script_body string and invokes the Lua
39   // function corresponding to function_name, passing in the corresponding
40   // published_data and saved_state arguments as Lua tables.
41   //
42   // Returns the output from executing the given script. If loading or
43   // invocation are unsuccessful, the errors are returned in the output.
44   std::vector<std::string> ExecuteScript(std::string script_body,
45                                          std::string function_name,
46                                          std::string published_data,
47                                          std::string saved_state);
48 
49   // Returns the saved state stored in the Lua registry of the LuaEngine
50   // instance, if any, in the form of a JSON string.
51   std::string GetSavedState();
52 
53   // Returns an allocated char** pointing to null-terminated equivalents
54   // of the strings within the vector passed in.
55   // Returns nullptr if the vector contains no elements.
56   //
57   // There is no std::vector<std::string> in C, so this type must be
58   // converted to a type usable by C, hence this utility function.
59   static char** StringVectorToCharArray(std::vector<std::string> vector);
60 
61  private:
62   // Invoked by a running Lua script to produce a log to the output. This is
63   // useful for debugging.
64   //
65   // This method returns 0 to indicate that no results were pushed to Lua
66   // stack according to Lua C function calling convention. More info:
67   // https://www.lua.org/manual/5.3/manual.html#lua_CFunction Usage in lua
68   // script:
69   //   log("selected gear: ", g)
70   static int ScriptLog(lua_State* lua);
71 
72   // Invoked by a running Lua script to store intermediate results.
73   // The script will provide the results as a Lua table. The result pushed by
74   // Lua is then forwarded to the Lua registry.
75   //
76   // The IDE supports nested fields in the table, but the actual
77   // ScriptExecutor currently supports boolean, number, integer, string, and
78   // their arrays. Refer to
79   // packages/services/Car/packages/ScriptExecutor/src/LuaEngine.h for the
80   // most up to date documentation on the supported types.
81   //
82   // This method returns 0 to indicate that no results were pushed to Lua
83   // stack according to Lua C function calling convention. More info:
84   // https://www.lua.org/manual/5.4/manual.html#lua_CFunction
85   static int OnSuccess(lua_State* lua);
86 
87   // Invoked by a running Lua script to effectively mark the completion of the
88   // script's lifecycle. The script will provide the final results as a Lua
89   // table. The result pushed by Lua is then forwarded to the
90   // output.
91   //
92   // The IDE supports nested fields in the table, but the actual
93   // ScriptExecutor currently supports boolean, number, integer, string, and
94   // their arrays. Refer to
95   // packages/services/Car/packages/ScriptExecutor/src/LuaEngine.h for the
96   // most up to date documentation on the supported types.
97   //
98   // This method returns 0 to indicate that no results were pushed to Lua
99   // stack according to Lua C function calling convention. More info:
100   // https://www.lua.org/manual/5.4/manual.html#lua_CFunction
101   static int OnScriptFinished(lua_State* lua);
102 
103   // Invoked by a running Lua script to indicate that an error occurred. This
104   // is the mechanism for a script author to receive error logs. The caller
105   // script encapsulates all the information about the error that the author
106   // wants to provide in a single string parameter. The error is
107   // then forwarded to the output.
108   //
109   // This method returns 0 to indicate that no results were pushed to Lua
110   // stack according to Lua C function calling convention. More info:
111   // https://www.lua.org/manual/5.4/manual.html#lua_CFunction
112   static int OnError(lua_State* lua);
113 
114   // Invoked by a running Lua script to produce a metrics report without
115   // completing the script's lifecycle, The script will provide the
116   // report as a Lua table. The report pushed by Lua is then forwarded to the
117   // output.
118   //
119   // on_metrics_report can also be used by a running Lua script to store
120   // intermediate results if the second argument is specified. The script
121   // will provide the results as a Lua table. The result pushed by Lua is then
122   // forwarded to the Lua registry.
123   //
124   // This method returns 0 to indicate that no results were pushed to
125   // Lua stack according to Lua C function calling convention. More info:
126   // https://www.lua.org/manual/5.4/manual.html#lua_CFunction Usage in lua
127   // script:
128   //   on_metrics_report(report_as_a_table)
129   //   on_metrics_report(report_as_a_table, saved_state_as_a_table)
130   static int OnMetricsReport(lua_State* lua);
131 
132   // Saves the saved_state to the Lua registry of the lua_State.
133   static void SaveSavedStateToRegistry(lua_State* lua, std::string saved_state);
134 
135   // Clears the current saved state in the Lua registry of the lua_State.
136   static void ClearSavedStateInRegistry(lua_State* lua);
137 
138   // Maintains the state of Lua.
139   lua_State* lua_state_;
140 
141   // Holds the metric reports and logs from the last script execution.
142   static std::vector<std::string> output_;
143 };
144 
145 // Adds compatibility with Python.
146 // Since Python is written in C, the external functions must be C callable (so
147 // C++ types must be converted to C compatible types). These are the functions
148 // that can be directly called on by the Python ctypes library.
149 extern "C" {
150 
151 // Holds information about the output of the execution.
152 struct LuaOutput {
153   // Holds the metric reports and logs from the last script execution.
154   char** output;
155 
156   // Details how many strings are within output.
157   //
158   // The output array doesn't have size information attached so
159   // the size of the array must be encoded in the struct for iteration (or risk
160   // Segmentation Faults from accessing random data).
161   int size;
162 
163   // Holds the saved state of the script execution, if any,
164   // in the form of a JSON string.
165   char* saved_state;
166 };
167 
168 // Frees up the memory used by the lua_output.
169 void FreeLuaOutput(LuaOutput* lua_output);
170 
171 // Creates a new instance of the LuaEngine.
172 LuaEngine* NewLuaEngine();
173 
174 // Loads Lua script provided as script_body string and invokes the Lua
175 // function corresponding to function_name, passing in the corresponding
176 // published_data and saved_state arguments as Lua tables.
177 //
178 // Allocates and returns the output from executing the given script in the
179 // form of the LuaOutput struct. If loading or invocation are unsuccessful, the
180 // errors are returned in the output.
181 LuaOutput* ExecuteScript(LuaEngine* l, char* script, char* function_name,
182                          char* published_data, char* saved_state);
183 }  // extern "C"
184 }  // namespace lua_interpreter
185 
186 #endif  // TOOLS_TELEMETRY_LUA_INTERPRETER_LUA_ENGINE_H_
187