1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Android utilities.
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuAndroidUtil.hpp"
25
26 #include "deSTLUtil.hpp"
27 #include "deMath.h"
28
29 #include <vector>
30
31 namespace tcu
32 {
33 namespace Android
34 {
35
36 using std::string;
37 using std::vector;
38
39 namespace
40 {
41
42 class ScopedJNIEnv
43 {
44 public:
45
46 ScopedJNIEnv (JavaVM* vm);
47 ~ScopedJNIEnv (void);
48
getVM(void) const49 JavaVM* getVM (void) const { return m_vm; }
getEnv(void) const50 JNIEnv* getEnv (void) const { return m_env; }
51
52 private:
53 JavaVM* const m_vm;
54 JNIEnv* m_env;
55 bool m_detach;
56 };
57
ScopedJNIEnv(JavaVM * vm)58 ScopedJNIEnv::ScopedJNIEnv (JavaVM* vm)
59 : m_vm (vm)
60 , m_env (DE_NULL)
61 , m_detach (false)
62 {
63 const int getEnvRes = m_vm->GetEnv((void**)&m_env, JNI_VERSION_1_6);
64
65 if (getEnvRes == JNI_EDETACHED)
66 {
67 if (m_vm->AttachCurrentThread(&m_env, DE_NULL) != JNI_OK)
68 throw std::runtime_error("JNI AttachCurrentThread() failed");
69
70 m_detach = true;
71 }
72 else if (getEnvRes != JNI_OK)
73 throw std::runtime_error("JNI GetEnv() failed");
74
75 DE_ASSERT(m_env);
76 }
77
~ScopedJNIEnv(void)78 ScopedJNIEnv::~ScopedJNIEnv (void)
79 {
80 if (m_detach)
81 m_vm->DetachCurrentThread();
82 }
83
84 class LocalRef
85 {
86 public:
87 LocalRef (JNIEnv* env, jobject ref);
88 ~LocalRef (void);
89
operator *(void) const90 jobject operator* (void) const { return m_ref; }
operator bool(void) const91 operator bool (void) const { return !!m_ref; }
92
93 private:
94 LocalRef (const LocalRef&);
95 LocalRef& operator= (const LocalRef&);
96
97 JNIEnv* const m_env;
98 const jobject m_ref;
99 };
100
LocalRef(JNIEnv * env,jobject ref)101 LocalRef::LocalRef (JNIEnv* env, jobject ref)
102 : m_env(env)
103 , m_ref(ref)
104 {
105 }
106
~LocalRef(void)107 LocalRef::~LocalRef (void)
108 {
109 if (m_ref)
110 m_env->DeleteLocalRef(m_ref);
111 }
112
checkException(JNIEnv * env)113 void checkException (JNIEnv* env)
114 {
115 if (env->ExceptionCheck())
116 {
117 env->ExceptionDescribe();
118 env->ExceptionClear();
119 throw std::runtime_error("Got JNI exception");
120 }
121 }
122
findClass(JNIEnv * env,const char * className)123 jclass findClass (JNIEnv* env, const char* className)
124 {
125 const jclass cls = env->FindClass(className);
126
127 checkException(env);
128 TCU_CHECK_INTERNAL(cls);
129
130 return cls;
131 }
132
getObjectClass(JNIEnv * env,jobject object)133 jclass getObjectClass (JNIEnv* env, jobject object)
134 {
135 const jclass cls = env->GetObjectClass(object);
136
137 checkException(env);
138 TCU_CHECK_INTERNAL(cls);
139
140 return cls;
141 }
142
getMethodID(JNIEnv * env,jclass cls,const char * methodName,const char * signature)143 jmethodID getMethodID (JNIEnv* env, jclass cls, const char* methodName, const char* signature)
144 {
145 const jmethodID id = env->GetMethodID(cls, methodName, signature);
146
147 checkException(env);
148 TCU_CHECK_INTERNAL(id);
149
150 return id;
151 }
152
getStringValue(JNIEnv * env,jstring jniStr)153 string getStringValue (JNIEnv* env, jstring jniStr)
154 {
155 const char* ptr = env->GetStringUTFChars(jniStr, DE_NULL);
156 const string str = string(ptr);
157
158 env->ReleaseStringUTFChars(jniStr, ptr);
159
160 return str;
161 }
162
getIntentStringExtra(JNIEnv * env,jobject activity,const char * name)163 string getIntentStringExtra (JNIEnv* env, jobject activity, const char* name)
164 {
165 // \todo [2013-05-12 pyry] Clean up references on error.
166
167 const jclass activityCls = getObjectClass(env, activity);
168 const LocalRef intent (env, env->CallObjectMethod(activity, getMethodID(env, activityCls, "getIntent", "()Landroid/content/Intent;")));
169 TCU_CHECK_INTERNAL(intent);
170
171 const LocalRef extraName (env, env->NewStringUTF(name));
172 const jclass intentCls = getObjectClass(env, *intent);
173 TCU_CHECK_INTERNAL(extraName && intentCls);
174
175 jvalue getExtraArgs[1];
176 getExtraArgs[0].l = *extraName;
177
178 const LocalRef extraStr (env, env->CallObjectMethodA(*intent, getMethodID(env, intentCls, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"), getExtraArgs));
179
180 if (extraStr)
181 return getStringValue(env, (jstring)*extraStr);
182 else
183 return string();
184 }
185
setRequestedOrientation(JNIEnv * env,jobject activity,ScreenOrientation orientation)186 void setRequestedOrientation (JNIEnv* env, jobject activity, ScreenOrientation orientation)
187 {
188 const jclass activityCls = getObjectClass(env, activity);
189 const jmethodID setOrientationId = getMethodID(env, activityCls, "setRequestedOrientation", "(I)V");
190
191 env->CallVoidMethod(activity, setOrientationId, (int)orientation);
192 }
193
194 template<typename Type>
195 const char* getJNITypeStr (void);
196
197 template<>
getJNITypeStr(void)198 const char* getJNITypeStr<int> (void)
199 {
200 return "I";
201 }
202
203 template<>
getJNITypeStr(void)204 const char* getJNITypeStr<deInt64> (void)
205 {
206 return "J";
207 }
208
209 template<>
getJNITypeStr(void)210 const char* getJNITypeStr<string> (void)
211 {
212 return "Ljava/lang/String;";
213 }
214
215 template<>
getJNITypeStr(void)216 const char* getJNITypeStr<vector<string> > (void)
217 {
218 return "[Ljava/lang/String;";
219 }
220
221 template<typename FieldType>
222 FieldType getStaticFieldValue (JNIEnv* env, jclass cls, jfieldID fieldId);
223
224 template<>
getStaticFieldValue(JNIEnv * env,jclass cls,jfieldID fieldId)225 int getStaticFieldValue<int> (JNIEnv* env, jclass cls, jfieldID fieldId)
226 {
227 DE_ASSERT(cls && fieldId);
228 return env->GetStaticIntField(cls, fieldId);
229 }
230
231 template<>
getStaticFieldValue(JNIEnv * env,jclass cls,jfieldID fieldId)232 string getStaticFieldValue<string> (JNIEnv* env, jclass cls, jfieldID fieldId)
233 {
234 const jstring jniStr = (jstring)env->GetStaticObjectField(cls, fieldId);
235
236 if (jniStr)
237 return getStringValue(env, jniStr);
238 else
239 return string();
240 }
241
242 template<>
getStaticFieldValue(JNIEnv * env,jclass cls,jfieldID fieldId)243 vector<string> getStaticFieldValue<vector<string> > (JNIEnv* env, jclass cls, jfieldID fieldId)
244 {
245 const jobjectArray array = (jobjectArray)env->GetStaticObjectField(cls, fieldId);
246 vector<string> result;
247
248 checkException(env);
249
250 if (array)
251 {
252 const int numElements = env->GetArrayLength(array);
253
254 for (int ndx = 0; ndx < numElements; ndx++)
255 {
256 const jstring jniStr = (jstring)env->GetObjectArrayElement(array, ndx);
257
258 checkException(env);
259
260 if (jniStr)
261 result.push_back(getStringValue(env, jniStr));
262 }
263 }
264
265 return result;
266 }
267
268 template<typename FieldType>
getStaticField(JNIEnv * env,const char * className,const char * fieldName)269 FieldType getStaticField (JNIEnv* env, const char* className, const char* fieldName)
270 {
271 const jclass cls = findClass(env, className);
272 const jfieldID fieldId = env->GetStaticFieldID(cls, fieldName, getJNITypeStr<FieldType>());
273
274 checkException(env);
275
276 if (fieldId)
277 return getStaticFieldValue<FieldType>(env, cls, fieldId);
278 else
279 throw std::runtime_error(string(fieldName) + " not found in " + className);
280 }
281
282 template<typename FieldType>
283 FieldType getFieldValue (JNIEnv* env, jobject obj, jfieldID fieldId);
284
285 template<>
getFieldValue(JNIEnv * env,jobject obj,jfieldID fieldId)286 deInt64 getFieldValue<deInt64> (JNIEnv* env, jobject obj, jfieldID fieldId)
287 {
288 DE_ASSERT(obj && fieldId);
289 return env->GetLongField(obj, fieldId);
290 }
291
292 template<typename FieldType>
getField(JNIEnv * env,jobject obj,const char * fieldName)293 FieldType getField (JNIEnv* env, jobject obj, const char* fieldName)
294 {
295 const jclass cls = getObjectClass(env, obj);
296 const jfieldID fieldId = env->GetFieldID(cls, fieldName, getJNITypeStr<FieldType>());
297
298 checkException(env);
299
300 if (fieldId)
301 return getFieldValue<FieldType>(env, obj, fieldId);
302 else
303 throw std::runtime_error(string(fieldName) + " not found in object");
304 }
305
describePlatform(JNIEnv * env,std::ostream & dst)306 void describePlatform (JNIEnv* env, std::ostream& dst)
307 {
308 const char* const buildClass = "android/os/Build";
309 const char* const versionClass = "android/os/Build$VERSION";
310
311 static const struct
312 {
313 const char* classPath;
314 const char* className;
315 const char* fieldName;
316 } s_stringFields[] =
317 {
318 { buildClass, "Build", "BOARD" },
319 { buildClass, "Build", "BRAND" },
320 { buildClass, "Build", "DEVICE" },
321 { buildClass, "Build", "DISPLAY" },
322 { buildClass, "Build", "FINGERPRINT" },
323 { buildClass, "Build", "HARDWARE" },
324 { buildClass, "Build", "MANUFACTURER" },
325 { buildClass, "Build", "MODEL" },
326 { buildClass, "Build", "PRODUCT" },
327 { buildClass, "Build", "TAGS" },
328 { buildClass, "Build", "TYPE" },
329 { versionClass, "Build.VERSION", "RELEASE" },
330 };
331
332 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_stringFields); ndx++)
333 dst << s_stringFields[ndx].className << "." << s_stringFields[ndx].fieldName
334 << ": " << getStaticField<string>(env, s_stringFields[ndx].classPath, s_stringFields[ndx].fieldName)
335 << "\n";
336
337 dst << "Build.VERSION.SDK_INT: " << getStaticField<int>(env, versionClass, "SDK_INT") << "\n";
338
339 {
340 const vector<string> supportedAbis = getStaticField<vector<string> >(env, buildClass, "SUPPORTED_ABIS");
341
342 dst << "Build.SUPPORTED_ABIS: ";
343
344 for (size_t ndx = 0; ndx < supportedAbis.size(); ndx++)
345 dst << (ndx != 0 ? ", " : "") << supportedAbis[ndx];
346
347 dst << "\n";
348 }
349 }
350
351 } // anonymous
352
mapScreenRotation(ScreenRotation rotation)353 ScreenOrientation mapScreenRotation (ScreenRotation rotation)
354 {
355 switch (rotation)
356 {
357 case SCREENROTATION_UNSPECIFIED: return SCREEN_ORIENTATION_UNSPECIFIED;
358 case SCREENROTATION_0: return SCREEN_ORIENTATION_PORTRAIT;
359 case SCREENROTATION_90: return SCREEN_ORIENTATION_LANDSCAPE;
360 case SCREENROTATION_180: return SCREEN_ORIENTATION_REVERSE_PORTRAIT;
361 case SCREENROTATION_270: return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
362 default:
363 print("Warning: Unsupported rotation");
364 return SCREEN_ORIENTATION_PORTRAIT;
365 }
366 }
367
getIntentStringExtra(ANativeActivity * activity,const char * name)368 string getIntentStringExtra (ANativeActivity* activity, const char* name)
369 {
370 const ScopedJNIEnv env(activity->vm);
371
372 return getIntentStringExtra(env.getEnv(), activity->clazz, name);
373 }
374
setRequestedOrientation(ANativeActivity * activity,ScreenOrientation orientation)375 void setRequestedOrientation (ANativeActivity* activity, ScreenOrientation orientation)
376 {
377 const ScopedJNIEnv env(activity->vm);
378
379 setRequestedOrientation(env.getEnv(), activity->clazz, orientation);
380 }
381
describePlatform(ANativeActivity * activity,std::ostream & dst)382 void describePlatform (ANativeActivity* activity, std::ostream& dst)
383 {
384 const ScopedJNIEnv env(activity->vm);
385
386 describePlatform(env.getEnv(), dst);
387 }
388
getTotalAndroidSystemMemory(ANativeActivity * activity)389 size_t getTotalAndroidSystemMemory (ANativeActivity* activity)
390 {
391 const ScopedJNIEnv scopedJniEnv (activity->vm);
392 JNIEnv* env = scopedJniEnv.getEnv();
393
394 // Get activity manager instance:
395 // ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
396 const jclass activityManagerClass = findClass(env, "android/app/ActivityManager");
397 const LocalRef activityString (env, env->NewStringUTF("activity")); // Context.ACTIVITY_SERVICE == "activity"
398 const jclass activityClass = getObjectClass(env, activity->clazz);
399 const jmethodID getServiceID = getMethodID(env, activityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
400 LocalRef activityManager (env, env->CallObjectMethod(activity->clazz, getServiceID, *activityString));
401 checkException(env);
402 TCU_CHECK_INTERNAL(activityManager);
403
404 // Crete memory info instance:
405 // ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
406 const jclass memoryInfoClass = findClass(env, "android/app/ActivityManager$MemoryInfo");
407 const jmethodID memoryInfoCtor = getMethodID(env, memoryInfoClass, "<init>", "()V");
408 LocalRef memoryInfo (env, env->NewObject(memoryInfoClass, memoryInfoCtor));
409 checkException(env);
410 TCU_CHECK_INTERNAL(memoryInfo);
411
412 // Get memory info from activity manager:
413 // activityManager.getMemoryInfo(memoryInfo);
414 const jmethodID getMemoryInfoID = getMethodID(env, activityManagerClass, "getMemoryInfo", "(Landroid/app/ActivityManager$MemoryInfo;)V");
415 checkException(env);
416 env->CallVoidMethod(*activityManager, getMemoryInfoID, *memoryInfo);
417
418 // Return 'totalMem' field from the memory info instance.
419 return static_cast<size_t>(getField<deInt64>(env, *memoryInfo, "totalMem"));
420 }
421
422 } // Android
423 } // tcu
424