aboutsummaryrefslogtreecommitdiff
path: root/cpp/telemetry
diff options
context:
space:
mode:
authorMax Dashouk <mdashouk@google.com>2021-05-20 14:19:32 -0700
committerMax Dashouk <mdashouk@google.com>2021-06-02 10:06:30 -0700
commite864dfcc54b6c5123d7f0afde7358edc394090c9 (patch)
tree2db6b31ac766ebe3e7cb04f9187c3f336bf93dd0 /cpp/telemetry
parent7983ec3cc36ee6bfc765e1e82a2a28eef6c987fe (diff)
downloadCar-e864dfcc54b6c5123d7f0afde7358edc394090c9.tar.gz
Add utility function that takes Java Bundle, converts it and pushes it
to Lua table. Adds relevant unit tests. Bug: 187517413 Test: atest JniUtilsTest Change-Id: I44a3f83efc5733c83506aad8897161e6f862f996
Diffstat (limited to 'cpp/telemetry')
-rw-r--r--cpp/telemetry/script_executor/Android.bp48
-rw-r--r--cpp/telemetry/script_executor/src/JniUtils.cpp95
-rw-r--r--cpp/telemetry/script_executor/src/JniUtils.h39
-rw-r--r--cpp/telemetry/script_executor/src/LuaEngine.cpp7
-rw-r--r--cpp/telemetry/script_executor/src/LuaEngine.h7
-rw-r--r--cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp138
6 files changed, 322 insertions, 12 deletions
diff --git a/cpp/telemetry/script_executor/Android.bp b/cpp/telemetry/script_executor/Android.bp
index 734d4ddb70..78b639a44a 100644
--- a/cpp/telemetry/script_executor/Android.bp
+++ b/cpp/telemetry/script_executor/Android.bp
@@ -16,13 +16,47 @@ package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
+cc_defaults {
+ name: "scriptexecutor_defaults",
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+ static_libs: [
+ "libbase",
+ "liblog",
+ "liblua",
+ ],
+}
+
cc_library {
- name: "script_executor",
- srcs: [
- "src/LuaEngine.cpp",
- ],
- static_libs: [
- "liblua",
- ],
+ name: "libscriptexecutor",
+ defaults: [
+ "scriptexecutor_defaults",
+ ],
+ srcs: [
+ "src/JniUtils.cpp",
+ "src/LuaEngine.cpp",
+ "src/ScriptExecutorListener.cpp",
+ ],
+ shared_libs: [
+ "libnativehelper",
+ ],
+ // Allow dependents to use the header files.
+ export_include_dirs: [
+ "src",
+ ],
}
+cc_library_shared {
+ name: "libscriptexecutorjniutils-test",
+ defaults: [
+ "scriptexecutor_defaults",
+ ],
+ srcs: [
+ "src/tests/JniUtilsTestHelper.cpp",
+ ],
+ shared_libs: [
+ "libnativehelper",
+ "libscriptexecutor",
+ ],
+}
diff --git a/cpp/telemetry/script_executor/src/JniUtils.cpp b/cpp/telemetry/script_executor/src/JniUtils.cpp
new file mode 100644
index 0000000000..93c1af89e6
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/JniUtils.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2021, 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.
+ */
+
+#include "JniUtils.h"
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle) {
+ lua_newtable(luaEngine->GetLuaState());
+ // null bundle object is allowed. We will treat it as an empty table.
+ if (bundle == nullptr) {
+ return;
+ }
+
+ // TODO(b/188832769): Consider caching some of these JNI references for
+ // performance reasons.
+ jclass bundleClass = env->FindClass("android/os/Bundle");
+ jmethodID getKeySetMethod = env->GetMethodID(bundleClass, "keySet", "()Ljava/util/Set;");
+ jobject keys = env->CallObjectMethod(bundle, getKeySetMethod);
+ jclass setClass = env->FindClass("java/util/Set");
+ jmethodID iteratorMethod = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
+ jobject keySetIteratorObject = env->CallObjectMethod(keys, iteratorMethod);
+
+ jclass iteratorClass = env->FindClass("java/util/Iterator");
+ jmethodID hasNextMethod = env->GetMethodID(iteratorClass, "hasNext", "()Z");
+ jmethodID nextMethod = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
+
+ jclass booleanClass = env->FindClass("java/lang/Boolean");
+ jclass integerClass = env->FindClass("java/lang/Integer");
+ jclass numberClass = env->FindClass("java/lang/Number");
+ jclass stringClass = env->FindClass("java/lang/String");
+ // TODO(b/188816922): Handle more types such as float and integer arrays,
+ // and perhaps nested Bundles.
+
+ jmethodID getMethod =
+ env->GetMethodID(bundleClass, "get", "(Ljava/lang/String;)Ljava/lang/Object;");
+
+ // Iterate over key set of the bundle one key at a time.
+ while (env->CallBooleanMethod(keySetIteratorObject, hasNextMethod)) {
+ // Read the value object that corresponds to this key.
+ jstring key = (jstring)env->CallObjectMethod(keySetIteratorObject, nextMethod);
+ jobject value = env->CallObjectMethod(bundle, getMethod, key);
+
+ // Get the value of the type, extract it accordingly from the bundle and
+ // push the extracted value and the key to the Lua table.
+ if (env->IsInstanceOf(value, booleanClass)) {
+ jmethodID boolMethod = env->GetMethodID(booleanClass, "booleanValue", "()Z");
+ bool boolValue = static_cast<bool>(env->CallBooleanMethod(value, boolMethod));
+ lua_pushboolean(luaEngine->GetLuaState(), boolValue);
+ } else if (env->IsInstanceOf(value, integerClass)) {
+ jmethodID intMethod = env->GetMethodID(integerClass, "intValue", "()I");
+ lua_pushinteger(luaEngine->GetLuaState(), env->CallIntMethod(value, intMethod));
+ } else if (env->IsInstanceOf(value, numberClass)) {
+ // Condense other numeric types using one class. Because lua supports only
+ // integer or double, and we handled integer in previous if clause.
+ jmethodID numberMethod = env->GetMethodID(numberClass, "doubleValue", "()D");
+ /* Pushes a double onto the stack */
+ lua_pushnumber(luaEngine->GetLuaState(), env->CallDoubleMethod(value, numberMethod));
+ } else if (env->IsInstanceOf(value, stringClass)) {
+ const char* rawStringValue = env->GetStringUTFChars((jstring)value, nullptr);
+ lua_pushstring(luaEngine->GetLuaState(), rawStringValue);
+ env->ReleaseStringUTFChars((jstring)value, rawStringValue);
+ } else {
+ // Other types are not implemented yet, skipping.
+ continue;
+ }
+
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ // table[rawKey] = value, where value is on top of the stack,
+ // and the table is the next element in the stack.
+ lua_setfield(luaEngine->GetLuaState(), /* idx= */ -2, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ }
+}
+
+} // namespace script_executor
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/telemetry/script_executor/src/JniUtils.h b/cpp/telemetry/script_executor/src/JniUtils.h
new file mode 100644
index 0000000000..c3ef6778e4
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/JniUtils.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021, 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.
+ */
+#ifndef CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_JNIUTILS_H_
+#define CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_JNIUTILS_H_
+
+#include "LuaEngine.h"
+#include "jni.h"
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+// Helper function which takes android.os.Bundle object in "bundle" argument
+// and converts it to Lua table on top of Lua stack. All key-value pairs are
+// converted to the corresponding key-value pairs of the Lua table as long as
+// the Bundle value types are supported. At this point, we support boolean,
+// integer, double and String types in Java.
+void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle);
+
+} // namespace script_executor
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_JNIUTILS_H_
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.cpp b/cpp/telemetry/script_executor/src/LuaEngine.cpp
index a8cace3c1c..cc1d0b8f62 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.cpp
+++ b/cpp/telemetry/script_executor/src/LuaEngine.cpp
@@ -28,8 +28,7 @@ namespace automotive {
namespace telemetry {
namespace script_executor {
-LuaEngine::LuaEngine(std::unique_ptr<ScriptExecutorListener> listener) :
- mListener(std::move(listener)) {
+LuaEngine::LuaEngine() {
mLuaState = luaL_newstate();
luaL_openlibs(mLuaState);
}
@@ -38,6 +37,10 @@ LuaEngine::~LuaEngine() {
lua_close(mLuaState);
}
+lua_State* LuaEngine::GetLuaState() {
+ return mLuaState;
+}
+
} // namespace script_executor
} // namespace telemetry
} // namespace automotive
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.h b/cpp/telemetry/script_executor/src/LuaEngine.h
index 086dbfe19b..a0f3978079 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.h
+++ b/cpp/telemetry/script_executor/src/LuaEngine.h
@@ -33,14 +33,15 @@ namespace script_executor {
// Encapsulates Lua script execution environment.
class LuaEngine {
public:
- explicit LuaEngine(std::unique_ptr<ScriptExecutorListener> listener);
+ LuaEngine();
virtual ~LuaEngine();
+ // Returns pointer to Lua state object.
+ lua_State* GetLuaState();
+
private:
lua_State* mLuaState; // owned
-
- std::unique_ptr<ScriptExecutorListener> mListener;
};
} // namespace script_executor
diff --git a/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
new file mode 100644
index 0000000000..9e2c43afd2
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2021, 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.
+ */
+
+#include "JniUtils.h"
+#include "LuaEngine.h"
+#include "jni.h"
+
+#include <cstdint>
+#include <cstring>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+namespace {
+
+extern "C" {
+
+#include "lua.h"
+
+JNIEXPORT jlong JNICALL
+Java_com_android_car_telemetry_JniUtilsTest_nativeCreateLuaEngine(JNIEnv* env, jobject object) {
+ // Cast first to intptr_t to ensure int can hold the pointer without loss.
+ return static_cast<jlong>(reinterpret_cast<intptr_t>(new LuaEngine()));
+}
+
+JNIEXPORT void JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeDestroyLuaEngine(
+ JNIEnv* env, jobject object, jlong luaEnginePtr) {
+ delete reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+}
+
+JNIEXPORT void JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativePushBundleToLuaTableCaller(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jobject bundle) {
+ PushBundleToLuaTable(env, reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr)),
+ bundle);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeGetObjectSize(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jint index) {
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ return lua_rawlen(engine->GetLuaState(), static_cast<int>(index));
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasBooleanValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jboolean value) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ auto* luaState = engine->GetLuaState();
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_isboolean(luaState, -1))
+ result = false;
+ else
+ result = static_cast<bool>(lua_toboolean(luaState, -1)) == static_cast<bool>(value);
+ lua_pop(luaState, 1);
+ return result;
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasIntValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jint value) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ // Assumes the table is on top of the stack.
+ auto* luaState = engine->GetLuaState();
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_isinteger(luaState, -1))
+ result = false;
+ else
+ result = lua_tointeger(luaState, -1) == static_cast<int>(value);
+ lua_pop(luaState, 1);
+ return result;
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasDoubleValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jdouble value) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ // Assumes the table is on top of the stack.
+ auto* luaState = engine->GetLuaState();
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_isnumber(luaState, -1))
+ result = false;
+ else
+ result = static_cast<double>(lua_tonumber(luaState, -1)) == static_cast<double>(value);
+ lua_pop(luaState, 1);
+ return result;
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasStringValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jstring value) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ // Assumes the table is on top of the stack.
+ auto* luaState = engine->GetLuaState();
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_isstring(luaState, -1)) {
+ result = false;
+ } else {
+ std::string s = lua_tostring(luaState, -1);
+ const char* rawValue = env->GetStringUTFChars(value, nullptr);
+ result = strcmp(lua_tostring(luaState, -1), rawValue) == 0;
+ env->ReleaseStringUTFChars(value, rawValue);
+ }
+ lua_pop(luaState, 1);
+ return result;
+}
+
+} // extern "C"
+
+} // namespace
+} // namespace script_executor
+} // namespace telemetry
+} // namespace automotive
+} // namespace android