1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker *
4*993b0882SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker *
8*993b0882SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker *
10*993b0882SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker */
16*993b0882SAndroid Build Coastguard Worker
17*993b0882SAndroid Build Coastguard Worker #include "utils/intents/jni-lua.h"
18*993b0882SAndroid Build Coastguard Worker
19*993b0882SAndroid Build Coastguard Worker #include "utils/hash/farmhash.h"
20*993b0882SAndroid Build Coastguard Worker #include "utils/java/jni-helper.h"
21*993b0882SAndroid Build Coastguard Worker #include "utils/strings/substitute.h"
22*993b0882SAndroid Build Coastguard Worker
23*993b0882SAndroid Build Coastguard Worker #ifdef __cplusplus
24*993b0882SAndroid Build Coastguard Worker extern "C" {
25*993b0882SAndroid Build Coastguard Worker #endif
26*993b0882SAndroid Build Coastguard Worker #include "lauxlib.h"
27*993b0882SAndroid Build Coastguard Worker #include "lua.h"
28*993b0882SAndroid Build Coastguard Worker #ifdef __cplusplus
29*993b0882SAndroid Build Coastguard Worker }
30*993b0882SAndroid Build Coastguard Worker #endif
31*993b0882SAndroid Build Coastguard Worker
32*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
33*993b0882SAndroid Build Coastguard Worker namespace {
34*993b0882SAndroid Build Coastguard Worker
35*993b0882SAndroid Build Coastguard Worker static constexpr const char* kHashKey = "hash";
36*993b0882SAndroid Build Coastguard Worker static constexpr const char* kUrlSchemaKey = "url_schema";
37*993b0882SAndroid Build Coastguard Worker static constexpr const char* kUrlHostKey = "url_host";
38*993b0882SAndroid Build Coastguard Worker static constexpr const char* kUrlEncodeKey = "urlencode";
39*993b0882SAndroid Build Coastguard Worker static constexpr const char* kPackageNameKey = "package_name";
40*993b0882SAndroid Build Coastguard Worker static constexpr const char* kDeviceLocaleKey = "device_locales";
41*993b0882SAndroid Build Coastguard Worker static constexpr const char* kFormatKey = "format";
42*993b0882SAndroid Build Coastguard Worker
43*993b0882SAndroid Build Coastguard Worker } // namespace
44*993b0882SAndroid Build Coastguard Worker
JniLuaEnvironment(const Resources & resources,const JniCache * jni_cache,const jobject context,const std::vector<Locale> & device_locales)45*993b0882SAndroid Build Coastguard Worker JniLuaEnvironment::JniLuaEnvironment(const Resources& resources,
46*993b0882SAndroid Build Coastguard Worker const JniCache* jni_cache,
47*993b0882SAndroid Build Coastguard Worker const jobject context,
48*993b0882SAndroid Build Coastguard Worker const std::vector<Locale>& device_locales)
49*993b0882SAndroid Build Coastguard Worker : LuaEnvironment(),
50*993b0882SAndroid Build Coastguard Worker resources_(resources),
51*993b0882SAndroid Build Coastguard Worker jenv_(jni_cache ? jni_cache->GetEnv() : nullptr),
52*993b0882SAndroid Build Coastguard Worker jni_cache_(jni_cache),
53*993b0882SAndroid Build Coastguard Worker context_(context),
54*993b0882SAndroid Build Coastguard Worker device_locales_(device_locales),
55*993b0882SAndroid Build Coastguard Worker usermanager_(/*object=*/nullptr,
56*993b0882SAndroid Build Coastguard Worker /*jvm=*/(jni_cache ? jni_cache->jvm : nullptr)),
57*993b0882SAndroid Build Coastguard Worker usermanager_retrieved_(false),
58*993b0882SAndroid Build Coastguard Worker system_resources_(/*object=*/nullptr,
59*993b0882SAndroid Build Coastguard Worker /*jvm=*/(jni_cache ? jni_cache->jvm : nullptr)),
60*993b0882SAndroid Build Coastguard Worker system_resources_resources_retrieved_(false),
61*993b0882SAndroid Build Coastguard Worker string_(/*object=*/nullptr,
62*993b0882SAndroid Build Coastguard Worker /*jvm=*/(jni_cache ? jni_cache->jvm : nullptr)),
63*993b0882SAndroid Build Coastguard Worker android_(/*object=*/nullptr,
64*993b0882SAndroid Build Coastguard Worker /*jvm=*/(jni_cache ? jni_cache->jvm : nullptr)) {}
65*993b0882SAndroid Build Coastguard Worker
PreallocateConstantJniStrings()66*993b0882SAndroid Build Coastguard Worker bool JniLuaEnvironment::PreallocateConstantJniStrings() {
67*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN_FALSE(ScopedLocalRef<jstring> string_value,
68*993b0882SAndroid Build Coastguard Worker JniHelper::NewStringUTF(jenv_, "string"));
69*993b0882SAndroid Build Coastguard Worker string_ = MakeGlobalRef(string_value.get(), jenv_, jni_cache_->jvm);
70*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN_FALSE(ScopedLocalRef<jstring> android_value,
71*993b0882SAndroid Build Coastguard Worker JniHelper::NewStringUTF(jenv_, "android"));
72*993b0882SAndroid Build Coastguard Worker android_ = MakeGlobalRef(android_value.get(), jenv_, jni_cache_->jvm);
73*993b0882SAndroid Build Coastguard Worker if (string_ == nullptr || android_ == nullptr) {
74*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Could not allocate constant strings references.";
75*993b0882SAndroid Build Coastguard Worker return false;
76*993b0882SAndroid Build Coastguard Worker }
77*993b0882SAndroid Build Coastguard Worker return true;
78*993b0882SAndroid Build Coastguard Worker }
79*993b0882SAndroid Build Coastguard Worker
Initialize()80*993b0882SAndroid Build Coastguard Worker bool JniLuaEnvironment::Initialize() {
81*993b0882SAndroid Build Coastguard Worker if (!PreallocateConstantJniStrings()) {
82*993b0882SAndroid Build Coastguard Worker return false;
83*993b0882SAndroid Build Coastguard Worker }
84*993b0882SAndroid Build Coastguard Worker return (RunProtected([this] {
85*993b0882SAndroid Build Coastguard Worker LoadDefaultLibraries();
86*993b0882SAndroid Build Coastguard Worker SetupExternalHook();
87*993b0882SAndroid Build Coastguard Worker lua_setglobal(state_, "external");
88*993b0882SAndroid Build Coastguard Worker return LUA_OK;
89*993b0882SAndroid Build Coastguard Worker }) == LUA_OK);
90*993b0882SAndroid Build Coastguard Worker }
91*993b0882SAndroid Build Coastguard Worker
SetupExternalHook()92*993b0882SAndroid Build Coastguard Worker void JniLuaEnvironment::SetupExternalHook() {
93*993b0882SAndroid Build Coastguard Worker // This exposes an `external` object with the following fields:
94*993b0882SAndroid Build Coastguard Worker // * entity: the bundle with all information about a classification.
95*993b0882SAndroid Build Coastguard Worker // * android: callbacks into specific android provided methods.
96*993b0882SAndroid Build Coastguard Worker // * android.user_restrictions: callbacks to check user permissions.
97*993b0882SAndroid Build Coastguard Worker // * android.R: callbacks to retrieve string resources.
98*993b0882SAndroid Build Coastguard Worker PushLazyObject(&JniLuaEnvironment::HandleExternalCallback);
99*993b0882SAndroid Build Coastguard Worker
100*993b0882SAndroid Build Coastguard Worker // android
101*993b0882SAndroid Build Coastguard Worker PushLazyObject(&JniLuaEnvironment::HandleAndroidCallback);
102*993b0882SAndroid Build Coastguard Worker {
103*993b0882SAndroid Build Coastguard Worker // android.user_restrictions
104*993b0882SAndroid Build Coastguard Worker PushLazyObject(&JniLuaEnvironment::HandleUserRestrictionsCallback);
105*993b0882SAndroid Build Coastguard Worker lua_setfield(state_, /*idx=*/-2, "user_restrictions");
106*993b0882SAndroid Build Coastguard Worker
107*993b0882SAndroid Build Coastguard Worker // android.R
108*993b0882SAndroid Build Coastguard Worker // Callback to access android string resources.
109*993b0882SAndroid Build Coastguard Worker PushLazyObject(&JniLuaEnvironment::HandleAndroidStringResources);
110*993b0882SAndroid Build Coastguard Worker lua_setfield(state_, /*idx=*/-2, "R");
111*993b0882SAndroid Build Coastguard Worker }
112*993b0882SAndroid Build Coastguard Worker lua_setfield(state_, /*idx=*/-2, "android");
113*993b0882SAndroid Build Coastguard Worker }
114*993b0882SAndroid Build Coastguard Worker
HandleExternalCallback()115*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::HandleExternalCallback() {
116*993b0882SAndroid Build Coastguard Worker const StringPiece key = ReadString(kIndexStackTop);
117*993b0882SAndroid Build Coastguard Worker if (key.Equals(kHashKey)) {
118*993b0882SAndroid Build Coastguard Worker PushFunction(&JniLuaEnvironment::HandleHash);
119*993b0882SAndroid Build Coastguard Worker return 1;
120*993b0882SAndroid Build Coastguard Worker } else if (key.Equals(kFormatKey)) {
121*993b0882SAndroid Build Coastguard Worker PushFunction(&JniLuaEnvironment::HandleFormat);
122*993b0882SAndroid Build Coastguard Worker return 1;
123*993b0882SAndroid Build Coastguard Worker } else {
124*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Undefined external access " << key;
125*993b0882SAndroid Build Coastguard Worker lua_error(state_);
126*993b0882SAndroid Build Coastguard Worker return 0;
127*993b0882SAndroid Build Coastguard Worker }
128*993b0882SAndroid Build Coastguard Worker }
129*993b0882SAndroid Build Coastguard Worker
HandleAndroidCallback()130*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::HandleAndroidCallback() {
131*993b0882SAndroid Build Coastguard Worker const StringPiece key = ReadString(kIndexStackTop);
132*993b0882SAndroid Build Coastguard Worker if (key.Equals(kDeviceLocaleKey)) {
133*993b0882SAndroid Build Coastguard Worker // Provide the locale as table with the individual fields set.
134*993b0882SAndroid Build Coastguard Worker lua_newtable(state_);
135*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < device_locales_.size(); i++) {
136*993b0882SAndroid Build Coastguard Worker // Adjust index to 1-based indexing for Lua.
137*993b0882SAndroid Build Coastguard Worker lua_pushinteger(state_, i + 1);
138*993b0882SAndroid Build Coastguard Worker lua_newtable(state_);
139*993b0882SAndroid Build Coastguard Worker PushString(device_locales_[i].Language());
140*993b0882SAndroid Build Coastguard Worker lua_setfield(state_, -2, "language");
141*993b0882SAndroid Build Coastguard Worker PushString(device_locales_[i].Region());
142*993b0882SAndroid Build Coastguard Worker lua_setfield(state_, -2, "region");
143*993b0882SAndroid Build Coastguard Worker PushString(device_locales_[i].Script());
144*993b0882SAndroid Build Coastguard Worker lua_setfield(state_, -2, "script");
145*993b0882SAndroid Build Coastguard Worker lua_settable(state_, /*idx=*/-3);
146*993b0882SAndroid Build Coastguard Worker }
147*993b0882SAndroid Build Coastguard Worker return 1;
148*993b0882SAndroid Build Coastguard Worker } else if (key.Equals(kPackageNameKey)) {
149*993b0882SAndroid Build Coastguard Worker if (context_ == nullptr) {
150*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Context invalid.";
151*993b0882SAndroid Build Coastguard Worker lua_error(state_);
152*993b0882SAndroid Build Coastguard Worker return 0;
153*993b0882SAndroid Build Coastguard Worker }
154*993b0882SAndroid Build Coastguard Worker
155*993b0882SAndroid Build Coastguard Worker StatusOr<ScopedLocalRef<jstring>> status_or_package_name_str =
156*993b0882SAndroid Build Coastguard Worker JniHelper::CallObjectMethod<jstring>(
157*993b0882SAndroid Build Coastguard Worker jenv_, context_, jni_cache_->context_get_package_name);
158*993b0882SAndroid Build Coastguard Worker
159*993b0882SAndroid Build Coastguard Worker if (!status_or_package_name_str.ok()) {
160*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error calling Context.getPackageName";
161*993b0882SAndroid Build Coastguard Worker lua_error(state_);
162*993b0882SAndroid Build Coastguard Worker return 0;
163*993b0882SAndroid Build Coastguard Worker }
164*993b0882SAndroid Build Coastguard Worker StatusOr<std::string> status_or_package_name_std_str = JStringToUtf8String(
165*993b0882SAndroid Build Coastguard Worker jenv_, status_or_package_name_str.ValueOrDie().get());
166*993b0882SAndroid Build Coastguard Worker if (!status_or_package_name_std_str.ok()) {
167*993b0882SAndroid Build Coastguard Worker lua_error(state_);
168*993b0882SAndroid Build Coastguard Worker return 0;
169*993b0882SAndroid Build Coastguard Worker }
170*993b0882SAndroid Build Coastguard Worker PushString(status_or_package_name_std_str.ValueOrDie());
171*993b0882SAndroid Build Coastguard Worker return 1;
172*993b0882SAndroid Build Coastguard Worker } else if (key.Equals(kUrlEncodeKey)) {
173*993b0882SAndroid Build Coastguard Worker PushFunction(&JniLuaEnvironment::HandleUrlEncode);
174*993b0882SAndroid Build Coastguard Worker return 1;
175*993b0882SAndroid Build Coastguard Worker } else if (key.Equals(kUrlHostKey)) {
176*993b0882SAndroid Build Coastguard Worker PushFunction(&JniLuaEnvironment::HandleUrlHost);
177*993b0882SAndroid Build Coastguard Worker return 1;
178*993b0882SAndroid Build Coastguard Worker } else if (key.Equals(kUrlSchemaKey)) {
179*993b0882SAndroid Build Coastguard Worker PushFunction(&JniLuaEnvironment::HandleUrlSchema);
180*993b0882SAndroid Build Coastguard Worker return 1;
181*993b0882SAndroid Build Coastguard Worker } else {
182*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Undefined android reference " << key;
183*993b0882SAndroid Build Coastguard Worker lua_error(state_);
184*993b0882SAndroid Build Coastguard Worker return 0;
185*993b0882SAndroid Build Coastguard Worker }
186*993b0882SAndroid Build Coastguard Worker }
187*993b0882SAndroid Build Coastguard Worker
HandleUserRestrictionsCallback()188*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::HandleUserRestrictionsCallback() {
189*993b0882SAndroid Build Coastguard Worker if (jni_cache_->usermanager_class == nullptr ||
190*993b0882SAndroid Build Coastguard Worker jni_cache_->usermanager_get_user_restrictions == nullptr) {
191*993b0882SAndroid Build Coastguard Worker // UserManager is only available for API level >= 17 and
192*993b0882SAndroid Build Coastguard Worker // getUserRestrictions only for API level >= 18, so we just return false
193*993b0882SAndroid Build Coastguard Worker // normally here.
194*993b0882SAndroid Build Coastguard Worker lua_pushboolean(state_, false);
195*993b0882SAndroid Build Coastguard Worker return 1;
196*993b0882SAndroid Build Coastguard Worker }
197*993b0882SAndroid Build Coastguard Worker
198*993b0882SAndroid Build Coastguard Worker // Get user manager if not previously retrieved.
199*993b0882SAndroid Build Coastguard Worker if (!RetrieveUserManager()) {
200*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error retrieving user manager.";
201*993b0882SAndroid Build Coastguard Worker lua_error(state_);
202*993b0882SAndroid Build Coastguard Worker return 0;
203*993b0882SAndroid Build Coastguard Worker }
204*993b0882SAndroid Build Coastguard Worker
205*993b0882SAndroid Build Coastguard Worker StatusOr<ScopedLocalRef<jobject>> status_or_bundle =
206*993b0882SAndroid Build Coastguard Worker JniHelper::CallObjectMethod(
207*993b0882SAndroid Build Coastguard Worker jenv_, usermanager_.get(),
208*993b0882SAndroid Build Coastguard Worker jni_cache_->usermanager_get_user_restrictions);
209*993b0882SAndroid Build Coastguard Worker if (!status_or_bundle.ok() || status_or_bundle.ValueOrDie() == nullptr) {
210*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error calling getUserRestrictions";
211*993b0882SAndroid Build Coastguard Worker lua_error(state_);
212*993b0882SAndroid Build Coastguard Worker return 0;
213*993b0882SAndroid Build Coastguard Worker }
214*993b0882SAndroid Build Coastguard Worker
215*993b0882SAndroid Build Coastguard Worker const StringPiece key_str = ReadString(kIndexStackTop);
216*993b0882SAndroid Build Coastguard Worker if (key_str.empty()) {
217*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Expected string, got null.";
218*993b0882SAndroid Build Coastguard Worker lua_error(state_);
219*993b0882SAndroid Build Coastguard Worker return 0;
220*993b0882SAndroid Build Coastguard Worker }
221*993b0882SAndroid Build Coastguard Worker
222*993b0882SAndroid Build Coastguard Worker const StatusOr<ScopedLocalRef<jstring>> status_or_key =
223*993b0882SAndroid Build Coastguard Worker jni_cache_->ConvertToJavaString(key_str);
224*993b0882SAndroid Build Coastguard Worker if (!status_or_key.ok()) {
225*993b0882SAndroid Build Coastguard Worker lua_error(state_);
226*993b0882SAndroid Build Coastguard Worker return 0;
227*993b0882SAndroid Build Coastguard Worker }
228*993b0882SAndroid Build Coastguard Worker const StatusOr<bool> status_or_permission = JniHelper::CallBooleanMethod(
229*993b0882SAndroid Build Coastguard Worker jenv_, status_or_bundle.ValueOrDie().get(),
230*993b0882SAndroid Build Coastguard Worker jni_cache_->bundle_get_boolean, status_or_key.ValueOrDie().get());
231*993b0882SAndroid Build Coastguard Worker if (!status_or_permission.ok()) {
232*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error getting bundle value";
233*993b0882SAndroid Build Coastguard Worker lua_pushboolean(state_, false);
234*993b0882SAndroid Build Coastguard Worker } else {
235*993b0882SAndroid Build Coastguard Worker lua_pushboolean(state_, status_or_permission.ValueOrDie());
236*993b0882SAndroid Build Coastguard Worker }
237*993b0882SAndroid Build Coastguard Worker return 1;
238*993b0882SAndroid Build Coastguard Worker }
239*993b0882SAndroid Build Coastguard Worker
HandleUrlEncode()240*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::HandleUrlEncode() {
241*993b0882SAndroid Build Coastguard Worker const StringPiece input = ReadString(/*index=*/1);
242*993b0882SAndroid Build Coastguard Worker if (input.empty()) {
243*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Expected string, got null.";
244*993b0882SAndroid Build Coastguard Worker lua_error(state_);
245*993b0882SAndroid Build Coastguard Worker return 0;
246*993b0882SAndroid Build Coastguard Worker }
247*993b0882SAndroid Build Coastguard Worker
248*993b0882SAndroid Build Coastguard Worker // Call Java Uri encode.
249*993b0882SAndroid Build Coastguard Worker const StatusOr<ScopedLocalRef<jstring>> status_or_input_str =
250*993b0882SAndroid Build Coastguard Worker jni_cache_->ConvertToJavaString(input);
251*993b0882SAndroid Build Coastguard Worker if (!status_or_input_str.ok()) {
252*993b0882SAndroid Build Coastguard Worker lua_error(state_);
253*993b0882SAndroid Build Coastguard Worker return 0;
254*993b0882SAndroid Build Coastguard Worker }
255*993b0882SAndroid Build Coastguard Worker StatusOr<ScopedLocalRef<jstring>> status_or_encoded_str =
256*993b0882SAndroid Build Coastguard Worker JniHelper::CallStaticObjectMethod<jstring>(
257*993b0882SAndroid Build Coastguard Worker jenv_, jni_cache_->uri_class.get(), jni_cache_->uri_encode,
258*993b0882SAndroid Build Coastguard Worker status_or_input_str.ValueOrDie().get());
259*993b0882SAndroid Build Coastguard Worker
260*993b0882SAndroid Build Coastguard Worker if (!status_or_encoded_str.ok()) {
261*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error calling Uri.encode";
262*993b0882SAndroid Build Coastguard Worker lua_error(state_);
263*993b0882SAndroid Build Coastguard Worker return 0;
264*993b0882SAndroid Build Coastguard Worker }
265*993b0882SAndroid Build Coastguard Worker const StatusOr<std::string> status_or_encoded_std_str =
266*993b0882SAndroid Build Coastguard Worker JStringToUtf8String(jenv_, status_or_encoded_str.ValueOrDie().get());
267*993b0882SAndroid Build Coastguard Worker if (!status_or_encoded_std_str.ok()) {
268*993b0882SAndroid Build Coastguard Worker lua_error(state_);
269*993b0882SAndroid Build Coastguard Worker return 0;
270*993b0882SAndroid Build Coastguard Worker }
271*993b0882SAndroid Build Coastguard Worker PushString(status_or_encoded_std_str.ValueOrDie());
272*993b0882SAndroid Build Coastguard Worker return 1;
273*993b0882SAndroid Build Coastguard Worker }
274*993b0882SAndroid Build Coastguard Worker
ParseUri(StringPiece url) const275*993b0882SAndroid Build Coastguard Worker StatusOr<ScopedLocalRef<jobject>> JniLuaEnvironment::ParseUri(
276*993b0882SAndroid Build Coastguard Worker StringPiece url) const {
277*993b0882SAndroid Build Coastguard Worker if (url.empty()) {
278*993b0882SAndroid Build Coastguard Worker return {Status::UNKNOWN};
279*993b0882SAndroid Build Coastguard Worker }
280*993b0882SAndroid Build Coastguard Worker
281*993b0882SAndroid Build Coastguard Worker // Call to Java URI parser.
282*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN(
283*993b0882SAndroid Build Coastguard Worker const StatusOr<ScopedLocalRef<jstring>> status_or_url_str,
284*993b0882SAndroid Build Coastguard Worker jni_cache_->ConvertToJavaString(url));
285*993b0882SAndroid Build Coastguard Worker
286*993b0882SAndroid Build Coastguard Worker // Try to parse uri and get scheme.
287*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN(
288*993b0882SAndroid Build Coastguard Worker ScopedLocalRef<jobject> uri,
289*993b0882SAndroid Build Coastguard Worker JniHelper::CallStaticObjectMethod(jenv_, jni_cache_->uri_class.get(),
290*993b0882SAndroid Build Coastguard Worker jni_cache_->uri_parse,
291*993b0882SAndroid Build Coastguard Worker status_or_url_str.ValueOrDie().get()));
292*993b0882SAndroid Build Coastguard Worker if (uri == nullptr) {
293*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error calling Uri.parse";
294*993b0882SAndroid Build Coastguard Worker return {Status::UNKNOWN};
295*993b0882SAndroid Build Coastguard Worker }
296*993b0882SAndroid Build Coastguard Worker return uri;
297*993b0882SAndroid Build Coastguard Worker }
298*993b0882SAndroid Build Coastguard Worker
HandleUrlSchema()299*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::HandleUrlSchema() {
300*993b0882SAndroid Build Coastguard Worker StringPiece url = ReadString(/*index=*/1);
301*993b0882SAndroid Build Coastguard Worker
302*993b0882SAndroid Build Coastguard Worker const StatusOr<ScopedLocalRef<jobject>> status_or_parsed_uri = ParseUri(url);
303*993b0882SAndroid Build Coastguard Worker if (!status_or_parsed_uri.ok()) {
304*993b0882SAndroid Build Coastguard Worker lua_error(state_);
305*993b0882SAndroid Build Coastguard Worker return 0;
306*993b0882SAndroid Build Coastguard Worker }
307*993b0882SAndroid Build Coastguard Worker
308*993b0882SAndroid Build Coastguard Worker const StatusOr<ScopedLocalRef<jstring>> status_or_scheme_str =
309*993b0882SAndroid Build Coastguard Worker JniHelper::CallObjectMethod<jstring>(
310*993b0882SAndroid Build Coastguard Worker jenv_, status_or_parsed_uri.ValueOrDie().get(),
311*993b0882SAndroid Build Coastguard Worker jni_cache_->uri_get_scheme);
312*993b0882SAndroid Build Coastguard Worker if (!status_or_scheme_str.ok()) {
313*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error calling Uri.getScheme";
314*993b0882SAndroid Build Coastguard Worker lua_error(state_);
315*993b0882SAndroid Build Coastguard Worker return 0;
316*993b0882SAndroid Build Coastguard Worker }
317*993b0882SAndroid Build Coastguard Worker if (status_or_scheme_str.ValueOrDie() == nullptr) {
318*993b0882SAndroid Build Coastguard Worker lua_pushnil(state_);
319*993b0882SAndroid Build Coastguard Worker } else {
320*993b0882SAndroid Build Coastguard Worker const StatusOr<std::string> status_or_scheme_std_str =
321*993b0882SAndroid Build Coastguard Worker JStringToUtf8String(jenv_, status_or_scheme_str.ValueOrDie().get());
322*993b0882SAndroid Build Coastguard Worker if (!status_or_scheme_std_str.ok()) {
323*993b0882SAndroid Build Coastguard Worker lua_error(state_);
324*993b0882SAndroid Build Coastguard Worker return 0;
325*993b0882SAndroid Build Coastguard Worker }
326*993b0882SAndroid Build Coastguard Worker PushString(status_or_scheme_std_str.ValueOrDie());
327*993b0882SAndroid Build Coastguard Worker }
328*993b0882SAndroid Build Coastguard Worker return 1;
329*993b0882SAndroid Build Coastguard Worker }
330*993b0882SAndroid Build Coastguard Worker
HandleUrlHost()331*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::HandleUrlHost() {
332*993b0882SAndroid Build Coastguard Worker const StringPiece url = ReadString(kIndexStackTop);
333*993b0882SAndroid Build Coastguard Worker
334*993b0882SAndroid Build Coastguard Worker const StatusOr<ScopedLocalRef<jobject>> status_or_parsed_uri = ParseUri(url);
335*993b0882SAndroid Build Coastguard Worker if (!status_or_parsed_uri.ok()) {
336*993b0882SAndroid Build Coastguard Worker lua_error(state_);
337*993b0882SAndroid Build Coastguard Worker return 0;
338*993b0882SAndroid Build Coastguard Worker }
339*993b0882SAndroid Build Coastguard Worker
340*993b0882SAndroid Build Coastguard Worker const StatusOr<ScopedLocalRef<jstring>> status_or_host_str =
341*993b0882SAndroid Build Coastguard Worker JniHelper::CallObjectMethod<jstring>(
342*993b0882SAndroid Build Coastguard Worker jenv_, status_or_parsed_uri.ValueOrDie().get(),
343*993b0882SAndroid Build Coastguard Worker jni_cache_->uri_get_host);
344*993b0882SAndroid Build Coastguard Worker if (!status_or_host_str.ok()) {
345*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error calling Uri.getHost";
346*993b0882SAndroid Build Coastguard Worker lua_error(state_);
347*993b0882SAndroid Build Coastguard Worker return 0;
348*993b0882SAndroid Build Coastguard Worker }
349*993b0882SAndroid Build Coastguard Worker
350*993b0882SAndroid Build Coastguard Worker if (status_or_host_str.ValueOrDie() == nullptr) {
351*993b0882SAndroid Build Coastguard Worker lua_pushnil(state_);
352*993b0882SAndroid Build Coastguard Worker } else {
353*993b0882SAndroid Build Coastguard Worker const StatusOr<std::string> status_or_host_std_str =
354*993b0882SAndroid Build Coastguard Worker JStringToUtf8String(jenv_, status_or_host_str.ValueOrDie().get());
355*993b0882SAndroid Build Coastguard Worker if (!status_or_host_std_str.ok()) {
356*993b0882SAndroid Build Coastguard Worker lua_error(state_);
357*993b0882SAndroid Build Coastguard Worker return 0;
358*993b0882SAndroid Build Coastguard Worker }
359*993b0882SAndroid Build Coastguard Worker PushString(status_or_host_std_str.ValueOrDie());
360*993b0882SAndroid Build Coastguard Worker }
361*993b0882SAndroid Build Coastguard Worker return 1;
362*993b0882SAndroid Build Coastguard Worker }
363*993b0882SAndroid Build Coastguard Worker
HandleHash()364*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::HandleHash() {
365*993b0882SAndroid Build Coastguard Worker const StringPiece input = ReadString(kIndexStackTop);
366*993b0882SAndroid Build Coastguard Worker lua_pushinteger(state_, tc3farmhash::Hash32(input.data(), input.length()));
367*993b0882SAndroid Build Coastguard Worker return 1;
368*993b0882SAndroid Build Coastguard Worker }
369*993b0882SAndroid Build Coastguard Worker
HandleFormat()370*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::HandleFormat() {
371*993b0882SAndroid Build Coastguard Worker const int num_args = lua_gettop(state_);
372*993b0882SAndroid Build Coastguard Worker std::vector<StringPiece> args(num_args - 1);
373*993b0882SAndroid Build Coastguard Worker for (int i = 0; i < num_args - 1; i++) {
374*993b0882SAndroid Build Coastguard Worker args[i] = ReadString(/*index=*/i + 2);
375*993b0882SAndroid Build Coastguard Worker }
376*993b0882SAndroid Build Coastguard Worker PushString(strings::Substitute(ReadString(/*index=*/1), args));
377*993b0882SAndroid Build Coastguard Worker return 1;
378*993b0882SAndroid Build Coastguard Worker }
379*993b0882SAndroid Build Coastguard Worker
LookupModelStringResource() const380*993b0882SAndroid Build Coastguard Worker bool JniLuaEnvironment::LookupModelStringResource() const {
381*993b0882SAndroid Build Coastguard Worker // Handle only lookup by name.
382*993b0882SAndroid Build Coastguard Worker if (lua_type(state_, kIndexStackTop) != LUA_TSTRING) {
383*993b0882SAndroid Build Coastguard Worker return false;
384*993b0882SAndroid Build Coastguard Worker }
385*993b0882SAndroid Build Coastguard Worker
386*993b0882SAndroid Build Coastguard Worker const StringPiece resource_name = ReadString(kIndexStackTop);
387*993b0882SAndroid Build Coastguard Worker std::string resource_content;
388*993b0882SAndroid Build Coastguard Worker if (!resources_.GetResourceContent(device_locales_, resource_name,
389*993b0882SAndroid Build Coastguard Worker &resource_content)) {
390*993b0882SAndroid Build Coastguard Worker // Resource cannot be provided by the model.
391*993b0882SAndroid Build Coastguard Worker return false;
392*993b0882SAndroid Build Coastguard Worker }
393*993b0882SAndroid Build Coastguard Worker
394*993b0882SAndroid Build Coastguard Worker PushString(resource_content);
395*993b0882SAndroid Build Coastguard Worker return true;
396*993b0882SAndroid Build Coastguard Worker }
397*993b0882SAndroid Build Coastguard Worker
HandleAndroidStringResources()398*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::HandleAndroidStringResources() {
399*993b0882SAndroid Build Coastguard Worker // Check whether the requested resource can be served from the model data.
400*993b0882SAndroid Build Coastguard Worker if (LookupModelStringResource()) {
401*993b0882SAndroid Build Coastguard Worker return 1;
402*993b0882SAndroid Build Coastguard Worker }
403*993b0882SAndroid Build Coastguard Worker
404*993b0882SAndroid Build Coastguard Worker // Get system resources if not previously retrieved.
405*993b0882SAndroid Build Coastguard Worker if (!RetrieveSystemResources()) {
406*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error retrieving system resources.";
407*993b0882SAndroid Build Coastguard Worker lua_error(state_);
408*993b0882SAndroid Build Coastguard Worker return 0;
409*993b0882SAndroid Build Coastguard Worker }
410*993b0882SAndroid Build Coastguard Worker
411*993b0882SAndroid Build Coastguard Worker int resource_id;
412*993b0882SAndroid Build Coastguard Worker switch (lua_type(state_, kIndexStackTop)) {
413*993b0882SAndroid Build Coastguard Worker case LUA_TNUMBER:
414*993b0882SAndroid Build Coastguard Worker resource_id = Read<int>(/*index=*/kIndexStackTop);
415*993b0882SAndroid Build Coastguard Worker break;
416*993b0882SAndroid Build Coastguard Worker case LUA_TSTRING: {
417*993b0882SAndroid Build Coastguard Worker const StringPiece resource_name_str = ReadString(kIndexStackTop);
418*993b0882SAndroid Build Coastguard Worker if (resource_name_str.empty()) {
419*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "No resource name provided.";
420*993b0882SAndroid Build Coastguard Worker lua_error(state_);
421*993b0882SAndroid Build Coastguard Worker return 0;
422*993b0882SAndroid Build Coastguard Worker }
423*993b0882SAndroid Build Coastguard Worker const StatusOr<ScopedLocalRef<jstring>> status_or_resource_name =
424*993b0882SAndroid Build Coastguard Worker jni_cache_->ConvertToJavaString(resource_name_str);
425*993b0882SAndroid Build Coastguard Worker if (!status_or_resource_name.ok()) {
426*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Invalid resource name.";
427*993b0882SAndroid Build Coastguard Worker lua_error(state_);
428*993b0882SAndroid Build Coastguard Worker return 0;
429*993b0882SAndroid Build Coastguard Worker }
430*993b0882SAndroid Build Coastguard Worker StatusOr<int> status_or_resource_id = JniHelper::CallIntMethod(
431*993b0882SAndroid Build Coastguard Worker jenv_, system_resources_.get(), jni_cache_->resources_get_identifier,
432*993b0882SAndroid Build Coastguard Worker status_or_resource_name.ValueOrDie().get(), string_.get(),
433*993b0882SAndroid Build Coastguard Worker android_.get());
434*993b0882SAndroid Build Coastguard Worker if (!status_or_resource_id.ok()) {
435*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error calling getIdentifier.";
436*993b0882SAndroid Build Coastguard Worker lua_error(state_);
437*993b0882SAndroid Build Coastguard Worker return 0;
438*993b0882SAndroid Build Coastguard Worker }
439*993b0882SAndroid Build Coastguard Worker resource_id = status_or_resource_id.ValueOrDie();
440*993b0882SAndroid Build Coastguard Worker break;
441*993b0882SAndroid Build Coastguard Worker }
442*993b0882SAndroid Build Coastguard Worker default:
443*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Unexpected type for resource lookup.";
444*993b0882SAndroid Build Coastguard Worker lua_error(state_);
445*993b0882SAndroid Build Coastguard Worker return 0;
446*993b0882SAndroid Build Coastguard Worker }
447*993b0882SAndroid Build Coastguard Worker if (resource_id == 0) {
448*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Resource not found.";
449*993b0882SAndroid Build Coastguard Worker lua_pushnil(state_);
450*993b0882SAndroid Build Coastguard Worker return 1;
451*993b0882SAndroid Build Coastguard Worker }
452*993b0882SAndroid Build Coastguard Worker StatusOr<ScopedLocalRef<jstring>> status_or_resource_str =
453*993b0882SAndroid Build Coastguard Worker JniHelper::CallObjectMethod<jstring>(jenv_, system_resources_.get(),
454*993b0882SAndroid Build Coastguard Worker jni_cache_->resources_get_string,
455*993b0882SAndroid Build Coastguard Worker resource_id);
456*993b0882SAndroid Build Coastguard Worker if (!status_or_resource_str.ok()) {
457*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Error calling getString.";
458*993b0882SAndroid Build Coastguard Worker lua_error(state_);
459*993b0882SAndroid Build Coastguard Worker return 0;
460*993b0882SAndroid Build Coastguard Worker }
461*993b0882SAndroid Build Coastguard Worker
462*993b0882SAndroid Build Coastguard Worker if (status_or_resource_str.ValueOrDie() == nullptr) {
463*993b0882SAndroid Build Coastguard Worker lua_pushnil(state_);
464*993b0882SAndroid Build Coastguard Worker } else {
465*993b0882SAndroid Build Coastguard Worker StatusOr<std::string> status_or_resource_std_str =
466*993b0882SAndroid Build Coastguard Worker JStringToUtf8String(jenv_, status_or_resource_str.ValueOrDie().get());
467*993b0882SAndroid Build Coastguard Worker if (!status_or_resource_std_str.ok()) {
468*993b0882SAndroid Build Coastguard Worker lua_error(state_);
469*993b0882SAndroid Build Coastguard Worker return 0;
470*993b0882SAndroid Build Coastguard Worker }
471*993b0882SAndroid Build Coastguard Worker PushString(status_or_resource_std_str.ValueOrDie());
472*993b0882SAndroid Build Coastguard Worker }
473*993b0882SAndroid Build Coastguard Worker return 1;
474*993b0882SAndroid Build Coastguard Worker }
475*993b0882SAndroid Build Coastguard Worker
RetrieveSystemResources()476*993b0882SAndroid Build Coastguard Worker bool JniLuaEnvironment::RetrieveSystemResources() {
477*993b0882SAndroid Build Coastguard Worker if (system_resources_resources_retrieved_) {
478*993b0882SAndroid Build Coastguard Worker return (system_resources_ != nullptr);
479*993b0882SAndroid Build Coastguard Worker }
480*993b0882SAndroid Build Coastguard Worker system_resources_resources_retrieved_ = true;
481*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN_FALSE(ScopedLocalRef<jobject> system_resources_ref,
482*993b0882SAndroid Build Coastguard Worker JniHelper::CallStaticObjectMethod(
483*993b0882SAndroid Build Coastguard Worker jenv_, jni_cache_->resources_class.get(),
484*993b0882SAndroid Build Coastguard Worker jni_cache_->resources_get_system));
485*993b0882SAndroid Build Coastguard Worker system_resources_ =
486*993b0882SAndroid Build Coastguard Worker MakeGlobalRef(system_resources_ref.get(), jenv_, jni_cache_->jvm);
487*993b0882SAndroid Build Coastguard Worker return (system_resources_ != nullptr);
488*993b0882SAndroid Build Coastguard Worker }
489*993b0882SAndroid Build Coastguard Worker
RetrieveUserManager()490*993b0882SAndroid Build Coastguard Worker bool JniLuaEnvironment::RetrieveUserManager() {
491*993b0882SAndroid Build Coastguard Worker if (context_ == nullptr) {
492*993b0882SAndroid Build Coastguard Worker return false;
493*993b0882SAndroid Build Coastguard Worker }
494*993b0882SAndroid Build Coastguard Worker if (usermanager_retrieved_) {
495*993b0882SAndroid Build Coastguard Worker return (usermanager_ != nullptr);
496*993b0882SAndroid Build Coastguard Worker }
497*993b0882SAndroid Build Coastguard Worker usermanager_retrieved_ = true;
498*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN_FALSE(const ScopedLocalRef<jstring> service,
499*993b0882SAndroid Build Coastguard Worker JniHelper::NewStringUTF(jenv_, "user"));
500*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN_FALSE(
501*993b0882SAndroid Build Coastguard Worker const ScopedLocalRef<jobject> usermanager_ref,
502*993b0882SAndroid Build Coastguard Worker JniHelper::CallObjectMethod(jenv_, context_,
503*993b0882SAndroid Build Coastguard Worker jni_cache_->context_get_system_service,
504*993b0882SAndroid Build Coastguard Worker service.get()));
505*993b0882SAndroid Build Coastguard Worker
506*993b0882SAndroid Build Coastguard Worker usermanager_ = MakeGlobalRef(usermanager_ref.get(), jenv_, jni_cache_->jvm);
507*993b0882SAndroid Build Coastguard Worker return (usermanager_ != nullptr);
508*993b0882SAndroid Build Coastguard Worker }
509*993b0882SAndroid Build Coastguard Worker
ReadRemoteActionTemplateResult() const510*993b0882SAndroid Build Coastguard Worker RemoteActionTemplate JniLuaEnvironment::ReadRemoteActionTemplateResult() const {
511*993b0882SAndroid Build Coastguard Worker RemoteActionTemplate result;
512*993b0882SAndroid Build Coastguard Worker // Read intent template.
513*993b0882SAndroid Build Coastguard Worker lua_pushnil(state_);
514*993b0882SAndroid Build Coastguard Worker while (Next(/*index=*/-2)) {
515*993b0882SAndroid Build Coastguard Worker const StringPiece key = ReadString(/*index=*/-2);
516*993b0882SAndroid Build Coastguard Worker if (key.Equals("title_without_entity")) {
517*993b0882SAndroid Build Coastguard Worker result.title_without_entity = Read<std::string>(/*index=*/kIndexStackTop);
518*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("title_with_entity")) {
519*993b0882SAndroid Build Coastguard Worker result.title_with_entity = Read<std::string>(/*index=*/kIndexStackTop);
520*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("description")) {
521*993b0882SAndroid Build Coastguard Worker result.description = Read<std::string>(/*index=*/kIndexStackTop);
522*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("description_with_app_name")) {
523*993b0882SAndroid Build Coastguard Worker result.description_with_app_name =
524*993b0882SAndroid Build Coastguard Worker Read<std::string>(/*index=*/kIndexStackTop);
525*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("action")) {
526*993b0882SAndroid Build Coastguard Worker result.action = Read<std::string>(/*index=*/kIndexStackTop);
527*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("data")) {
528*993b0882SAndroid Build Coastguard Worker result.data = Read<std::string>(/*index=*/kIndexStackTop);
529*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("type")) {
530*993b0882SAndroid Build Coastguard Worker result.type = Read<std::string>(/*index=*/kIndexStackTop);
531*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("flags")) {
532*993b0882SAndroid Build Coastguard Worker result.flags = Read<int>(/*index=*/kIndexStackTop);
533*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("package_name")) {
534*993b0882SAndroid Build Coastguard Worker result.package_name = Read<std::string>(/*index=*/kIndexStackTop);
535*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("request_code")) {
536*993b0882SAndroid Build Coastguard Worker result.request_code = Read<int>(/*index=*/kIndexStackTop);
537*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("category")) {
538*993b0882SAndroid Build Coastguard Worker result.category = ReadVector<std::string>(/*index=*/kIndexStackTop);
539*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("extra")) {
540*993b0882SAndroid Build Coastguard Worker result.extra = ReadExtras();
541*993b0882SAndroid Build Coastguard Worker } else {
542*993b0882SAndroid Build Coastguard Worker TC3_LOG(INFO) << "Unknown entry: " << key;
543*993b0882SAndroid Build Coastguard Worker }
544*993b0882SAndroid Build Coastguard Worker lua_pop(state_, 1);
545*993b0882SAndroid Build Coastguard Worker }
546*993b0882SAndroid Build Coastguard Worker lua_pop(state_, 1);
547*993b0882SAndroid Build Coastguard Worker return result;
548*993b0882SAndroid Build Coastguard Worker }
549*993b0882SAndroid Build Coastguard Worker
ReadExtras() const550*993b0882SAndroid Build Coastguard Worker std::map<std::string, Variant> JniLuaEnvironment::ReadExtras() const {
551*993b0882SAndroid Build Coastguard Worker if (lua_type(state_, kIndexStackTop) != LUA_TTABLE) {
552*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Expected extras table, got: "
553*993b0882SAndroid Build Coastguard Worker << lua_type(state_, kIndexStackTop);
554*993b0882SAndroid Build Coastguard Worker lua_pop(state_, 1);
555*993b0882SAndroid Build Coastguard Worker return {};
556*993b0882SAndroid Build Coastguard Worker }
557*993b0882SAndroid Build Coastguard Worker std::map<std::string, Variant> extras;
558*993b0882SAndroid Build Coastguard Worker lua_pushnil(state_);
559*993b0882SAndroid Build Coastguard Worker while (Next(/*index=*/-2)) {
560*993b0882SAndroid Build Coastguard Worker // Each entry is a table specifying name and value.
561*993b0882SAndroid Build Coastguard Worker // The value is specified via a type specific field as Lua doesn't allow
562*993b0882SAndroid Build Coastguard Worker // to easily distinguish between different number types.
563*993b0882SAndroid Build Coastguard Worker if (lua_type(state_, kIndexStackTop) != LUA_TTABLE) {
564*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Expected a table for an extra, got: "
565*993b0882SAndroid Build Coastguard Worker << lua_type(state_, kIndexStackTop);
566*993b0882SAndroid Build Coastguard Worker lua_pop(state_, 1);
567*993b0882SAndroid Build Coastguard Worker return {};
568*993b0882SAndroid Build Coastguard Worker }
569*993b0882SAndroid Build Coastguard Worker std::string name;
570*993b0882SAndroid Build Coastguard Worker Variant value;
571*993b0882SAndroid Build Coastguard Worker
572*993b0882SAndroid Build Coastguard Worker lua_pushnil(state_);
573*993b0882SAndroid Build Coastguard Worker while (Next(/*index=*/-2)) {
574*993b0882SAndroid Build Coastguard Worker const StringPiece key = ReadString(/*index=*/-2);
575*993b0882SAndroid Build Coastguard Worker if (key.Equals("name")) {
576*993b0882SAndroid Build Coastguard Worker name = Read<std::string>(/*index=*/kIndexStackTop);
577*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("int_value")) {
578*993b0882SAndroid Build Coastguard Worker value = Variant(Read<int>(/*index=*/kIndexStackTop));
579*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("long_value")) {
580*993b0882SAndroid Build Coastguard Worker value = Variant(Read<int64>(/*index=*/kIndexStackTop));
581*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("float_value")) {
582*993b0882SAndroid Build Coastguard Worker value = Variant(Read<float>(/*index=*/kIndexStackTop));
583*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("bool_value")) {
584*993b0882SAndroid Build Coastguard Worker value = Variant(Read<bool>(/*index=*/kIndexStackTop));
585*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("string_value")) {
586*993b0882SAndroid Build Coastguard Worker value = Variant(Read<std::string>(/*index=*/kIndexStackTop));
587*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("string_array_value")) {
588*993b0882SAndroid Build Coastguard Worker value = Variant(ReadVector<std::string>(/*index=*/kIndexStackTop));
589*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("float_array_value")) {
590*993b0882SAndroid Build Coastguard Worker value = Variant(ReadVector<float>(/*index=*/kIndexStackTop));
591*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("int_array_value")) {
592*993b0882SAndroid Build Coastguard Worker value = Variant(ReadVector<int>(/*index=*/kIndexStackTop));
593*993b0882SAndroid Build Coastguard Worker } else if (key.Equals("named_variant_array_value")) {
594*993b0882SAndroid Build Coastguard Worker value = Variant(ReadExtras());
595*993b0882SAndroid Build Coastguard Worker } else {
596*993b0882SAndroid Build Coastguard Worker TC3_LOG(INFO) << "Unknown extra field: " << key;
597*993b0882SAndroid Build Coastguard Worker }
598*993b0882SAndroid Build Coastguard Worker lua_pop(state_, 1);
599*993b0882SAndroid Build Coastguard Worker }
600*993b0882SAndroid Build Coastguard Worker if (!name.empty()) {
601*993b0882SAndroid Build Coastguard Worker extras[name] = value;
602*993b0882SAndroid Build Coastguard Worker } else {
603*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Unnamed extra entry. Skipping.";
604*993b0882SAndroid Build Coastguard Worker }
605*993b0882SAndroid Build Coastguard Worker lua_pop(state_, 1);
606*993b0882SAndroid Build Coastguard Worker }
607*993b0882SAndroid Build Coastguard Worker return extras;
608*993b0882SAndroid Build Coastguard Worker }
609*993b0882SAndroid Build Coastguard Worker
ReadRemoteActionTemplates(std::vector<RemoteActionTemplate> * result)610*993b0882SAndroid Build Coastguard Worker int JniLuaEnvironment::ReadRemoteActionTemplates(
611*993b0882SAndroid Build Coastguard Worker std::vector<RemoteActionTemplate>* result) {
612*993b0882SAndroid Build Coastguard Worker // Read result.
613*993b0882SAndroid Build Coastguard Worker if (lua_type(state_, kIndexStackTop) != LUA_TTABLE) {
614*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Unexpected result for snippet: "
615*993b0882SAndroid Build Coastguard Worker << lua_type(state_, kIndexStackTop);
616*993b0882SAndroid Build Coastguard Worker lua_error(state_);
617*993b0882SAndroid Build Coastguard Worker return LUA_ERRRUN;
618*993b0882SAndroid Build Coastguard Worker }
619*993b0882SAndroid Build Coastguard Worker
620*993b0882SAndroid Build Coastguard Worker // Read remote action templates array.
621*993b0882SAndroid Build Coastguard Worker lua_pushnil(state_);
622*993b0882SAndroid Build Coastguard Worker while (Next(/*index=*/-2)) {
623*993b0882SAndroid Build Coastguard Worker if (lua_type(state_, kIndexStackTop) != LUA_TTABLE) {
624*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Expected intent table, got: "
625*993b0882SAndroid Build Coastguard Worker << lua_type(state_, kIndexStackTop);
626*993b0882SAndroid Build Coastguard Worker lua_pop(state_, 1);
627*993b0882SAndroid Build Coastguard Worker continue;
628*993b0882SAndroid Build Coastguard Worker }
629*993b0882SAndroid Build Coastguard Worker result->push_back(ReadRemoteActionTemplateResult());
630*993b0882SAndroid Build Coastguard Worker }
631*993b0882SAndroid Build Coastguard Worker lua_pop(state_, /*n=*/1);
632*993b0882SAndroid Build Coastguard Worker return LUA_OK;
633*993b0882SAndroid Build Coastguard Worker }
634*993b0882SAndroid Build Coastguard Worker
RunIntentGenerator(const std::string & generator_snippet,std::vector<RemoteActionTemplate> * remote_actions)635*993b0882SAndroid Build Coastguard Worker bool JniLuaEnvironment::RunIntentGenerator(
636*993b0882SAndroid Build Coastguard Worker const std::string& generator_snippet,
637*993b0882SAndroid Build Coastguard Worker std::vector<RemoteActionTemplate>* remote_actions) {
638*993b0882SAndroid Build Coastguard Worker int status;
639*993b0882SAndroid Build Coastguard Worker status = luaL_loadbuffer(state_, generator_snippet.data(),
640*993b0882SAndroid Build Coastguard Worker generator_snippet.size(),
641*993b0882SAndroid Build Coastguard Worker /*name=*/nullptr);
642*993b0882SAndroid Build Coastguard Worker if (status != LUA_OK) {
643*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Couldn't load generator snippet: " << status;
644*993b0882SAndroid Build Coastguard Worker return false;
645*993b0882SAndroid Build Coastguard Worker }
646*993b0882SAndroid Build Coastguard Worker status = lua_pcall(state_, /*nargs=*/0, /*nresults=*/1, /*errfunc=*/0);
647*993b0882SAndroid Build Coastguard Worker if (status != LUA_OK) {
648*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Couldn't run generator snippet: " << status;
649*993b0882SAndroid Build Coastguard Worker return false;
650*993b0882SAndroid Build Coastguard Worker }
651*993b0882SAndroid Build Coastguard Worker if (RunProtected(
652*993b0882SAndroid Build Coastguard Worker [this, remote_actions] {
653*993b0882SAndroid Build Coastguard Worker return ReadRemoteActionTemplates(remote_actions);
654*993b0882SAndroid Build Coastguard Worker },
655*993b0882SAndroid Build Coastguard Worker /*num_args=*/1) != LUA_OK) {
656*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Could not read results.";
657*993b0882SAndroid Build Coastguard Worker return false;
658*993b0882SAndroid Build Coastguard Worker }
659*993b0882SAndroid Build Coastguard Worker // Check that we correctly cleaned-up the state.
660*993b0882SAndroid Build Coastguard Worker const int stack_size = lua_gettop(state_);
661*993b0882SAndroid Build Coastguard Worker if (stack_size > 0) {
662*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Unexpected stack size.";
663*993b0882SAndroid Build Coastguard Worker lua_settop(state_, 0);
664*993b0882SAndroid Build Coastguard Worker return false;
665*993b0882SAndroid Build Coastguard Worker }
666*993b0882SAndroid Build Coastguard Worker return true;
667*993b0882SAndroid Build Coastguard Worker }
668*993b0882SAndroid Build Coastguard Worker
669*993b0882SAndroid Build Coastguard Worker } // namespace libtextclassifier3
670