1 /*
2  * Copyright (c) 2021, 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 PACKAGES_SCRIPTEXECUTOR_SRC_LUAENGINE_H_
18 #define PACKAGES_SCRIPTEXECUTOR_SRC_LUAENGINE_H_
19 
20 #include "ScriptExecutorListener.h"
21 
22 #include <memory>
23 
24 extern "C" {
25 #include "lua.h"
26 }
27 
28 namespace com {
29 namespace android {
30 namespace car {
31 namespace scriptexecutor {
32 
33 // Encapsulates Lua script execution environment.
34 class LuaEngine {
35 public:
36     LuaEngine();
37 
38     virtual ~LuaEngine();
39 
40     // Returns pointer to Lua state object.
41     lua_State* getLuaState();
42 
43     // Loads Lua script provided as scriptBody string.
44     // Returns 0 if successful. Otherwise returns non-zero Lua error code.
45     int loadScript(const char* scriptBody);
46 
47     // Pushes a Lua function under provided name into the stack.
48     // Returns 1 if successful. Otherwise, an error is sent back to the client via the callback
49     // and 0 is returned.
50     int pushFunction(const char* functionName);
51 
52     // Invokes function with the inputs provided in the stack.
53     // Assumes that the script body has been already loaded and successfully
54     // compiled and run, and all input arguments, and the function have been
55     // pushed to the stack.
56     // Returns 0 if successful. Otherwise returns non-zero Lua error code
57     // and sends the error via a callback back to the client.
58     int run();
59 
60     // Updates stored listener and destroys the previous one.
61     static void resetListener(ScriptExecutorListener* listener);
62 
63 private:
64     // Invoked by a running Lua script to store intermediate results.
65     // The script will provide the results as a Lua table.
66     // We currently support only non-nested fields in the table and the fields can be the following
67     // Lua types: boolean, number, integer, and string.
68     // The result pushed by Lua is converted to PersistableBundle and forwarded to
69     // ScriptExecutor service via callback interface.
70     // This method returns 0 to indicate that no results were pushed to Lua stack according
71     // to Lua C function calling convention.
72     // More info: https://www.lua.org/manual/5.3/manual.html#lua_CFunction
73     static int onSuccess(lua_State* lua);
74 
75     // Invoked by a running Lua script to effectively mark the completion of the script's lifecycle,
76     // and send the final results to CarTelemetryService and then to the user.
77     // The script will provide the final results as a Lua table.
78     // We currently support only non-nested fields in the table and the fields can be the following
79     // Lua types: boolean, number, integer, and string.
80     // The result pushed by Lua is converted to Android PersistableBundle and forwarded to
81     // ScriptExecutor service via callback interface.
82     // This method returns 0 to indicate that no results were pushed to Lua stack according
83     // to Lua C function calling convention.
84     // More info: https://www.lua.org/manual/5.3/manual.html#lua_CFunction
85     static int onScriptFinished(lua_State* lua);
86 
87     // Invoked by a running Lua script to indicate than an error occurred. This is the mechanism to
88     // for a script author to receive error logs. The caller script encapsulates all the information
89     // about the error that the author wants to provide in a single string parameter.
90     // This method returns 0 to indicate that no results were pushed to Lua stack according
91     // to Lua C function calling convention.
92     // More info: https://www.lua.org/manual/5.3/manual.html#lua_CFunction
93     static int onError(lua_State* lua);
94 
95     // Points to the current listener object.
96     // Lua cannot call non-static class methods. We need to access listener object instance in
97     // Lua callbacks. Therefore, callbacks callable by Lua are static class methods and the pointer
98     // to a listener object needs to be static, since static methods cannot access non-static
99     // members.
100     // Only one listener is supported at any given time.
101     // Since listeners are heap-allocated, the destructor does not need to run at shutdown
102     // of the service because the memory allocated to the current listener object will be
103     // reclaimed by the OS.
104     static ScriptExecutorListener* sListener;
105 
106     lua_State* mLuaState;  // owned
107 };
108 
109 }  // namespace scriptexecutor
110 }  // namespace car
111 }  // namespace android
112 }  // namespace com
113 
114 #endif  // PACKAGES_SCRIPTEXECUTOR_SRC_LUAENGINE_H_
115