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 "BundleWrapper.h"
18
19 #include "JniUtils.h"
20 #include "jni.h"
21 #include "nativehelper/scoped_local_ref.h"
22
23 namespace com {
24 namespace android {
25 namespace car {
26 namespace scriptexecutor {
27
28 using ::android::base::Error;
29 using ::android::base::Result;
30
BundleWrapper(JNIEnv * env)31 BundleWrapper::BundleWrapper(JNIEnv* env) {
32 mJNIEnv = env;
33 ScopedLocalRef<jclass> localBundleClassRef(mJNIEnv,
34 mJNIEnv->FindClass("android/os/PersistableBundle"));
35 mBundleClass = static_cast<jclass>(mJNIEnv->NewGlobalRef(localBundleClassRef.get()));
36
37 jmethodID bundleConstructor = mJNIEnv->GetMethodID(mBundleClass, "<init>", "()V");
38 ScopedLocalRef<jobject> localBundleObjectRef(mJNIEnv,
39 mJNIEnv->NewObject(mBundleClass,
40 bundleConstructor));
41 mBundle = mJNIEnv->NewGlobalRef(localBundleObjectRef.get());
42 }
43
~BundleWrapper()44 BundleWrapper::~BundleWrapper() {
45 // Delete global JNI references.
46 if (mBundle != NULL) {
47 mJNIEnv->DeleteGlobalRef(mBundle);
48 }
49 if (mBundleClass != NULL) {
50 mJNIEnv->DeleteGlobalRef(mBundleClass);
51 }
52 }
53
putBoolean(const char * key,bool value)54 Result<void> BundleWrapper::putBoolean(const char* key, bool value) {
55 ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
56 if (keyStringRef == nullptr) {
57 return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
58 }
59
60 // TODO(b/188832769): consider caching the references.
61 jmethodID putBooleanMethod =
62 mJNIEnv->GetMethodID(mBundleClass, "putBoolean", "(Ljava/lang/String;Z)V");
63 mJNIEnv->CallVoidMethod(mBundle, putBooleanMethod, keyStringRef.get(),
64 static_cast<jboolean>(value));
65 return {}; // ok result
66 }
67
putLong(const char * key,int64_t value)68 Result<void> BundleWrapper::putLong(const char* key, int64_t value) {
69 ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
70 if (keyStringRef == nullptr) {
71 return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
72 }
73
74 jmethodID putLongMethod =
75 mJNIEnv->GetMethodID(mBundleClass, "putLong", "(Ljava/lang/String;J)V");
76 mJNIEnv->CallVoidMethod(mBundle, putLongMethod, keyStringRef.get(), static_cast<jlong>(value));
77 return {}; // ok result
78 }
79
putDouble(const char * key,double value)80 Result<void> BundleWrapper::putDouble(const char* key, double value) {
81 ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
82 if (keyStringRef == nullptr) {
83 return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
84 }
85
86 jmethodID putDoubleMethod =
87 mJNIEnv->GetMethodID(mBundleClass, "putDouble", "(Ljava/lang/String;D)V");
88 mJNIEnv->CallVoidMethod(mBundle, putDoubleMethod, keyStringRef.get(),
89 static_cast<jdouble>(value));
90 return {}; // ok result
91 }
92
putString(const char * key,const char * value)93 Result<void> BundleWrapper::putString(const char* key, const char* value) {
94 jmethodID putStringMethod = mJNIEnv->GetMethodID(mBundleClass, "putString",
95 "(Ljava/lang/String;Ljava/lang/String;)V");
96 ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
97 if (keyStringRef == nullptr) {
98 return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
99 }
100
101 ScopedLocalRef<jstring> valueStringRef(mJNIEnv, mJNIEnv->NewStringUTF(value));
102 if (valueStringRef == nullptr) {
103 return Error() << "Failed to create a string for the provided value due to OOM error";
104 }
105
106 mJNIEnv->CallVoidMethod(mBundle, putStringMethod, keyStringRef.get(), valueStringRef.get());
107 return {}; // ok result
108 }
109
putBooleanArray(const char * key,const std::vector<unsigned char> & value)110 Result<void> BundleWrapper::putBooleanArray(const char* key,
111 const std::vector<unsigned char>& value) {
112 ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
113 if (keyStringRef == nullptr) {
114 return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
115 }
116
117 jmethodID putBooleanArrayMethod =
118 mJNIEnv->GetMethodID(mBundleClass, "putBooleanArray", "(Ljava/lang/String;[Z)V");
119
120 ScopedLocalRef<jbooleanArray> arrayRef(mJNIEnv, mJNIEnv->NewBooleanArray(value.size()));
121 mJNIEnv->SetBooleanArrayRegion(arrayRef.get(), 0, value.size(), &value.at(0));
122 mJNIEnv->CallVoidMethod(mBundle, putBooleanArrayMethod, keyStringRef.get(), arrayRef.get());
123 return {}; // ok result
124 }
125
putDoubleArray(const char * key,const std::vector<double> & value)126 Result<void> BundleWrapper::putDoubleArray(const char* key, const std::vector<double>& value) {
127 ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
128 if (keyStringRef == nullptr) {
129 return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
130 }
131
132 jmethodID putDoubleArrayMethod =
133 mJNIEnv->GetMethodID(mBundleClass, "putDoubleArray", "(Ljava/lang/String;[D)V");
134
135 ScopedLocalRef<jdoubleArray> arrayRef(mJNIEnv, mJNIEnv->NewDoubleArray(value.size()));
136 mJNIEnv->SetDoubleArrayRegion(arrayRef.get(), 0, value.size(), &value[0]);
137 mJNIEnv->CallVoidMethod(mBundle, putDoubleArrayMethod, keyStringRef.get(), arrayRef.get());
138 return {}; // ok result
139 }
140
putLongArray(const char * key,const std::vector<int64_t> & value)141 Result<void> BundleWrapper::putLongArray(const char* key, const std::vector<int64_t>& value) {
142 ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
143 if (keyStringRef == nullptr) {
144 return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
145 }
146
147 jmethodID putLongArrayMethod =
148 mJNIEnv->GetMethodID(mBundleClass, "putLongArray", "(Ljava/lang/String;[J)V");
149
150 ScopedLocalRef<jlongArray> arrayRef(mJNIEnv, mJNIEnv->NewLongArray(value.size()));
151 mJNIEnv->SetLongArrayRegion(arrayRef.get(), 0, value.size(), &value[0]);
152 mJNIEnv->CallVoidMethod(mBundle, putLongArrayMethod, keyStringRef.get(), arrayRef.get());
153 return {}; // ok result
154 }
155
putStringArray(const char * key,const std::vector<std::string> & value)156 Result<void> BundleWrapper::putStringArray(const char* key, const std::vector<std::string>& value) {
157 ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
158 if (keyStringRef == nullptr) {
159 return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
160 }
161
162 jmethodID putStringArrayMethod =
163 mJNIEnv->GetMethodID(mBundleClass, "putStringArray",
164 "(Ljava/lang/String;[Ljava/lang/String;)V");
165
166 ScopedLocalRef<jclass> stringClassRef(mJNIEnv, mJNIEnv->FindClass("java/lang/String"));
167 ScopedLocalRef<jobjectArray> arrayRef(mJNIEnv,
168 mJNIEnv->NewObjectArray(value.size(),
169 mJNIEnv->FindClass(
170 "java/lang/String"),
171 nullptr));
172 for (int i = 0; i < value.size(); i++) {
173 ScopedLocalRef<jstring> valueStringRef(mJNIEnv, mJNIEnv->NewStringUTF(value[i].c_str()));
174 if (valueStringRef == nullptr) {
175 return Error() << "Failed to create a string for provided value due to OOM error";
176 }
177 mJNIEnv->SetObjectArrayElement(arrayRef.get(), i, valueStringRef.get());
178 }
179 mJNIEnv->CallVoidMethod(mBundle, putStringArrayMethod, keyStringRef.get(), arrayRef.get());
180 return {}; // ok result
181 }
182
putPersistableBundle(const char * key,const BundleWrapper & value)183 Result<void> BundleWrapper::putPersistableBundle(const char* key, const BundleWrapper& value) {
184 jmethodID putPersistableBundleMethod =
185 mJNIEnv->GetMethodID(mBundleClass, "putPersistableBundle",
186 "(Ljava/lang/String;Landroid/os/PersistableBundle;)V");
187 ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
188 if (keyStringRef == nullptr) {
189 return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
190 }
191 mJNIEnv->CallVoidMethod(mBundle, putPersistableBundleMethod, keyStringRef.get(),
192 value.getBundle());
193 return {}; // ok result
194 }
195
getBundle() const196 jobject BundleWrapper::getBundle() const {
197 return mBundle;
198 }
199
200 } // namespace scriptexecutor
201 } // namespace car
202 } // namespace android
203 } // namespace com
204