• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "JniUtils.h"
18 
19 namespace android {
20 namespace automotive {
21 namespace telemetry {
22 namespace script_executor {
23 
PushBundleToLuaTable(JNIEnv * env,LuaEngine * luaEngine,jobject bundle)24 void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle) {
25     lua_newtable(luaEngine->GetLuaState());
26     // null bundle object is allowed. We will treat it as an empty table.
27     if (bundle == nullptr) {
28         return;
29     }
30 
31     // TODO(b/188832769): Consider caching some of these JNI references for
32     // performance reasons.
33     jclass bundleClass = env->FindClass("android/os/Bundle");
34     jmethodID getKeySetMethod = env->GetMethodID(bundleClass, "keySet", "()Ljava/util/Set;");
35     jobject keys = env->CallObjectMethod(bundle, getKeySetMethod);
36     jclass setClass = env->FindClass("java/util/Set");
37     jmethodID iteratorMethod = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
38     jobject keySetIteratorObject = env->CallObjectMethod(keys, iteratorMethod);
39 
40     jclass iteratorClass = env->FindClass("java/util/Iterator");
41     jmethodID hasNextMethod = env->GetMethodID(iteratorClass, "hasNext", "()Z");
42     jmethodID nextMethod = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
43 
44     jclass booleanClass = env->FindClass("java/lang/Boolean");
45     jclass integerClass = env->FindClass("java/lang/Integer");
46     jclass numberClass = env->FindClass("java/lang/Number");
47     jclass stringClass = env->FindClass("java/lang/String");
48     // TODO(b/188816922): Handle more types such as float and integer arrays,
49     // and perhaps nested Bundles.
50 
51     jmethodID getMethod =
52             env->GetMethodID(bundleClass, "get", "(Ljava/lang/String;)Ljava/lang/Object;");
53 
54     // Iterate over key set of the bundle one key at a time.
55     while (env->CallBooleanMethod(keySetIteratorObject, hasNextMethod)) {
56         // Read the value object that corresponds to this key.
57         jstring key = (jstring)env->CallObjectMethod(keySetIteratorObject, nextMethod);
58         jobject value = env->CallObjectMethod(bundle, getMethod, key);
59 
60         // Get the value of the type, extract it accordingly from the bundle and
61         // push the extracted value and the key to the Lua table.
62         if (env->IsInstanceOf(value, booleanClass)) {
63             jmethodID boolMethod = env->GetMethodID(booleanClass, "booleanValue", "()Z");
64             bool boolValue = static_cast<bool>(env->CallBooleanMethod(value, boolMethod));
65             lua_pushboolean(luaEngine->GetLuaState(), boolValue);
66         } else if (env->IsInstanceOf(value, integerClass)) {
67             jmethodID intMethod = env->GetMethodID(integerClass, "intValue", "()I");
68             lua_pushinteger(luaEngine->GetLuaState(), env->CallIntMethod(value, intMethod));
69         } else if (env->IsInstanceOf(value, numberClass)) {
70             // Condense other numeric types using one class. Because lua supports only
71             // integer or double, and we handled integer in previous if clause.
72             jmethodID numberMethod = env->GetMethodID(numberClass, "doubleValue", "()D");
73             /* Pushes a double onto the stack */
74             lua_pushnumber(luaEngine->GetLuaState(), env->CallDoubleMethod(value, numberMethod));
75         } else if (env->IsInstanceOf(value, stringClass)) {
76             const char* rawStringValue = env->GetStringUTFChars((jstring)value, nullptr);
77             lua_pushstring(luaEngine->GetLuaState(), rawStringValue);
78             env->ReleaseStringUTFChars((jstring)value, rawStringValue);
79         } else {
80             // Other types are not implemented yet, skipping.
81             continue;
82         }
83 
84         const char* rawKey = env->GetStringUTFChars(key, nullptr);
85         // table[rawKey] = value, where value is on top of the stack,
86         // and the table is the next element in the stack.
87         lua_setfield(luaEngine->GetLuaState(), /* idx= */ -2, rawKey);
88         env->ReleaseStringUTFChars(key, rawKey);
89     }
90 }
91 
92 }  // namespace script_executor
93 }  // namespace telemetry
94 }  // namespace automotive
95 }  // namespace android
96