xref: /aosp_15_r20/external/deqp/framework/platform/android/tcuAndroidUtil.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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     ScopedJNIEnv(JavaVM *vm);
46     ~ScopedJNIEnv(void);
47 
getVM(void) const48     JavaVM *getVM(void) const
49     {
50         return m_vm;
51     }
getEnv(void) const52     JNIEnv *getEnv(void) const
53     {
54         return m_env;
55     }
56 
57 private:
58     JavaVM *const m_vm;
59     JNIEnv *m_env;
60     bool m_detach;
61 };
62 
ScopedJNIEnv(JavaVM * vm)63 ScopedJNIEnv::ScopedJNIEnv(JavaVM *vm) : m_vm(vm), m_env(DE_NULL), m_detach(false)
64 {
65     const int getEnvRes = m_vm->GetEnv((void **)&m_env, JNI_VERSION_1_6);
66 
67     if (getEnvRes == JNI_EDETACHED)
68     {
69         if (m_vm->AttachCurrentThread(&m_env, DE_NULL) != JNI_OK)
70             throw std::runtime_error("JNI AttachCurrentThread() failed");
71 
72         m_detach = true;
73     }
74     else if (getEnvRes != JNI_OK)
75         throw std::runtime_error("JNI GetEnv() failed");
76 
77     DE_ASSERT(m_env);
78 }
79 
~ScopedJNIEnv(void)80 ScopedJNIEnv::~ScopedJNIEnv(void)
81 {
82     if (m_detach)
83         m_vm->DetachCurrentThread();
84 }
85 
86 class LocalRef
87 {
88 public:
89     LocalRef(JNIEnv *env, jobject ref);
90     ~LocalRef(void);
91 
operator *(void) const92     jobject operator*(void) const
93     {
94         return m_ref;
95     }
operator bool(void) const96     operator bool(void) const
97     {
98         return !!m_ref;
99     }
100 
101 private:
102     LocalRef(const LocalRef &);
103     LocalRef &operator=(const LocalRef &);
104 
105     JNIEnv *const m_env;
106     const jobject m_ref;
107 };
108 
LocalRef(JNIEnv * env,jobject ref)109 LocalRef::LocalRef(JNIEnv *env, jobject ref) : m_env(env), m_ref(ref)
110 {
111 }
112 
~LocalRef(void)113 LocalRef::~LocalRef(void)
114 {
115     if (m_ref)
116         m_env->DeleteLocalRef(m_ref);
117 }
118 
checkException(JNIEnv * env)119 void checkException(JNIEnv *env)
120 {
121     if (env->ExceptionCheck())
122     {
123         env->ExceptionDescribe();
124         env->ExceptionClear();
125         throw std::runtime_error("Got JNI exception");
126     }
127 }
128 
findClass(JNIEnv * env,const char * className)129 jclass findClass(JNIEnv *env, const char *className)
130 {
131     const jclass cls = env->FindClass(className);
132 
133     checkException(env);
134     TCU_CHECK_INTERNAL(cls);
135 
136     return cls;
137 }
138 
getObjectClass(JNIEnv * env,jobject object)139 jclass getObjectClass(JNIEnv *env, jobject object)
140 {
141     const jclass cls = env->GetObjectClass(object);
142 
143     checkException(env);
144     TCU_CHECK_INTERNAL(cls);
145 
146     return cls;
147 }
148 
getMethodID(JNIEnv * env,jclass cls,const char * methodName,const char * signature)149 jmethodID getMethodID(JNIEnv *env, jclass cls, const char *methodName, const char *signature)
150 {
151     const jmethodID id = env->GetMethodID(cls, methodName, signature);
152 
153     checkException(env);
154     TCU_CHECK_INTERNAL(id);
155 
156     return id;
157 }
158 
getStringValue(JNIEnv * env,jstring jniStr)159 string getStringValue(JNIEnv *env, jstring jniStr)
160 {
161     const char *ptr  = env->GetStringUTFChars(jniStr, DE_NULL);
162     const string str = string(ptr);
163 
164     env->ReleaseStringUTFChars(jniStr, ptr);
165 
166     return str;
167 }
168 
getIntentStringExtra(JNIEnv * env,jobject activity,const char * name)169 string getIntentStringExtra(JNIEnv *env, jobject activity, const char *name)
170 {
171     // \todo [2013-05-12 pyry] Clean up references on error.
172 
173     const jclass activityCls = getObjectClass(env, activity);
174     const LocalRef intent(
175         env, env->CallObjectMethod(activity, getMethodID(env, activityCls, "getIntent", "()Landroid/content/Intent;")));
176     TCU_CHECK_INTERNAL(intent);
177 
178     const LocalRef extraName(env, env->NewStringUTF(name));
179     const jclass intentCls = getObjectClass(env, *intent);
180     TCU_CHECK_INTERNAL(extraName && intentCls);
181 
182     jvalue getExtraArgs[1];
183     getExtraArgs[0].l = *extraName;
184 
185     const LocalRef extraStr(env, env->CallObjectMethodA(*intent,
186                                                         getMethodID(env, intentCls, "getStringExtra",
187                                                                     "(Ljava/lang/String;)Ljava/lang/String;"),
188                                                         getExtraArgs));
189 
190     if (extraStr)
191         return getStringValue(env, (jstring)*extraStr);
192     else
193         return string();
194 }
195 
setRequestedOrientation(JNIEnv * env,jobject activity,ScreenOrientation orientation)196 void setRequestedOrientation(JNIEnv *env, jobject activity, ScreenOrientation orientation)
197 {
198     const jclass activityCls         = getObjectClass(env, activity);
199     const jmethodID setOrientationId = getMethodID(env, activityCls, "setRequestedOrientation", "(I)V");
200 
201     env->CallVoidMethod(activity, setOrientationId, (int)orientation);
202 }
203 
204 template <typename Type>
205 const char *getJNITypeStr(void);
206 
207 template <>
getJNITypeStr(void)208 const char *getJNITypeStr<int>(void)
209 {
210     return "I";
211 }
212 
213 template <>
getJNITypeStr(void)214 const char *getJNITypeStr<int64_t>(void)
215 {
216     return "J";
217 }
218 
219 template <>
getJNITypeStr(void)220 const char *getJNITypeStr<string>(void)
221 {
222     return "Ljava/lang/String;";
223 }
224 
225 template <>
getJNITypeStr(void)226 const char *getJNITypeStr<vector<string>>(void)
227 {
228     return "[Ljava/lang/String;";
229 }
230 
231 template <typename FieldType>
232 FieldType getStaticFieldValue(JNIEnv *env, jclass cls, jfieldID fieldId);
233 
234 template <>
getStaticFieldValue(JNIEnv * env,jclass cls,jfieldID fieldId)235 int getStaticFieldValue<int>(JNIEnv *env, jclass cls, jfieldID fieldId)
236 {
237     DE_ASSERT(cls && fieldId);
238     return env->GetStaticIntField(cls, fieldId);
239 }
240 
241 template <>
getStaticFieldValue(JNIEnv * env,jclass cls,jfieldID fieldId)242 string getStaticFieldValue<string>(JNIEnv *env, jclass cls, jfieldID fieldId)
243 {
244     const jstring jniStr = (jstring)env->GetStaticObjectField(cls, fieldId);
245 
246     if (jniStr)
247         return getStringValue(env, jniStr);
248     else
249         return string();
250 }
251 
252 template <>
getStaticFieldValue(JNIEnv * env,jclass cls,jfieldID fieldId)253 vector<string> getStaticFieldValue<vector<string>>(JNIEnv *env, jclass cls, jfieldID fieldId)
254 {
255     const jobjectArray array = (jobjectArray)env->GetStaticObjectField(cls, fieldId);
256     vector<string> result;
257 
258     checkException(env);
259 
260     if (array)
261     {
262         const int numElements = env->GetArrayLength(array);
263 
264         for (int ndx = 0; ndx < numElements; ndx++)
265         {
266             const jstring jniStr = (jstring)env->GetObjectArrayElement(array, ndx);
267 
268             checkException(env);
269 
270             if (jniStr)
271                 result.push_back(getStringValue(env, jniStr));
272         }
273     }
274 
275     return result;
276 }
277 
278 template <typename FieldType>
getStaticField(JNIEnv * env,const char * className,const char * fieldName)279 FieldType getStaticField(JNIEnv *env, const char *className, const char *fieldName)
280 {
281     const jclass cls       = findClass(env, className);
282     const jfieldID fieldId = env->GetStaticFieldID(cls, fieldName, getJNITypeStr<FieldType>());
283 
284     checkException(env);
285 
286     if (fieldId)
287         return getStaticFieldValue<FieldType>(env, cls, fieldId);
288     else
289         throw std::runtime_error(string(fieldName) + " not found in " + className);
290 }
291 
292 template <typename FieldType>
293 FieldType getFieldValue(JNIEnv *env, jobject obj, jfieldID fieldId);
294 
295 template <>
getFieldValue(JNIEnv * env,jobject obj,jfieldID fieldId)296 int64_t getFieldValue<int64_t>(JNIEnv *env, jobject obj, jfieldID fieldId)
297 {
298     DE_ASSERT(obj && fieldId);
299     return env->GetLongField(obj, fieldId);
300 }
301 
302 template <typename FieldType>
getField(JNIEnv * env,jobject obj,const char * fieldName)303 FieldType getField(JNIEnv *env, jobject obj, const char *fieldName)
304 {
305     const jclass cls       = getObjectClass(env, obj);
306     const jfieldID fieldId = env->GetFieldID(cls, fieldName, getJNITypeStr<FieldType>());
307 
308     checkException(env);
309 
310     if (fieldId)
311         return getFieldValue<FieldType>(env, obj, fieldId);
312     else
313         throw std::runtime_error(string(fieldName) + " not found in object");
314 }
315 
describePlatform(JNIEnv * env,std::ostream & dst)316 void describePlatform(JNIEnv *env, std::ostream &dst)
317 {
318     const char *const buildClass   = "android/os/Build";
319     const char *const versionClass = "android/os/Build$VERSION";
320 
321     static const struct
322     {
323         const char *classPath;
324         const char *className;
325         const char *fieldName;
326     } s_stringFields[] = {
327         {buildClass, "Build", "BOARD"},        {buildClass, "Build", "BRAND"},
328         {buildClass, "Build", "DEVICE"},       {buildClass, "Build", "DISPLAY"},
329         {buildClass, "Build", "FINGERPRINT"},  {buildClass, "Build", "HARDWARE"},
330         {buildClass, "Build", "MANUFACTURER"}, {buildClass, "Build", "MODEL"},
331         {buildClass, "Build", "PRODUCT"},      {buildClass, "Build", "TAGS"},
332         {buildClass, "Build", "TYPE"},         {versionClass, "Build.VERSION", "RELEASE"},
333     };
334 
335     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_stringFields); ndx++)
336         dst << s_stringFields[ndx].className << "." << s_stringFields[ndx].fieldName << ": "
337             << getStaticField<string>(env, s_stringFields[ndx].classPath, s_stringFields[ndx].fieldName) << "\n";
338 
339     dst << "Build.VERSION.SDK_INT: " << getStaticField<int>(env, versionClass, "SDK_INT") << "\n";
340 
341     {
342         const vector<string> supportedAbis = getStaticField<vector<string>>(env, buildClass, "SUPPORTED_ABIS");
343 
344         dst << "Build.SUPPORTED_ABIS: ";
345 
346         for (size_t ndx = 0; ndx < supportedAbis.size(); ndx++)
347             dst << (ndx != 0 ? ", " : "") << supportedAbis[ndx];
348 
349         dst << "\n";
350     }
351 }
352 
353 } // namespace
354 
mapScreenRotation(ScreenRotation rotation)355 ScreenOrientation mapScreenRotation(ScreenRotation rotation)
356 {
357     switch (rotation)
358     {
359     case SCREENROTATION_UNSPECIFIED:
360         return SCREEN_ORIENTATION_UNSPECIFIED;
361     case SCREENROTATION_0:
362         return SCREEN_ORIENTATION_PORTRAIT;
363     case SCREENROTATION_90:
364         return SCREEN_ORIENTATION_LANDSCAPE;
365     case SCREENROTATION_180:
366         return SCREEN_ORIENTATION_REVERSE_PORTRAIT;
367     case SCREENROTATION_270:
368         return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
369     default:
370         print("Warning: Unsupported rotation");
371         return SCREEN_ORIENTATION_PORTRAIT;
372     }
373 }
374 
getIntentStringExtra(ANativeActivity * activity,const char * name)375 string getIntentStringExtra(ANativeActivity *activity, const char *name)
376 {
377     const ScopedJNIEnv env(activity->vm);
378 
379     return getIntentStringExtra(env.getEnv(), activity->clazz, name);
380 }
381 
setRequestedOrientation(ANativeActivity * activity,ScreenOrientation orientation)382 void setRequestedOrientation(ANativeActivity *activity, ScreenOrientation orientation)
383 {
384     const ScopedJNIEnv env(activity->vm);
385 
386     setRequestedOrientation(env.getEnv(), activity->clazz, orientation);
387 }
388 
describePlatform(ANativeActivity * activity,std::ostream & dst)389 void describePlatform(ANativeActivity *activity, std::ostream &dst)
390 {
391     const ScopedJNIEnv env(activity->vm);
392 
393     describePlatform(env.getEnv(), dst);
394 }
395 
getTotalAndroidSystemMemory(ANativeActivity * activity)396 size_t getTotalAndroidSystemMemory(ANativeActivity *activity)
397 {
398     const ScopedJNIEnv scopedJniEnv(activity->vm);
399     JNIEnv *env = scopedJniEnv.getEnv();
400 
401     // Get activity manager instance:
402     // ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
403     const jclass activityManagerClass = findClass(env, "android/app/ActivityManager");
404     const LocalRef activityString(env, env->NewStringUTF("activity")); // Context.ACTIVITY_SERVICE == "activity"
405     const jclass activityClass = getObjectClass(env, activity->clazz);
406     const jmethodID getServiceID =
407         getMethodID(env, activityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
408     LocalRef activityManager(env, env->CallObjectMethod(activity->clazz, getServiceID, *activityString));
409     checkException(env);
410     TCU_CHECK_INTERNAL(activityManager);
411 
412     // Crete memory info instance:
413     // ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
414     const jclass memoryInfoClass   = findClass(env, "android/app/ActivityManager$MemoryInfo");
415     const jmethodID memoryInfoCtor = getMethodID(env, memoryInfoClass, "<init>", "()V");
416     LocalRef memoryInfo(env, env->NewObject(memoryInfoClass, memoryInfoCtor));
417     checkException(env);
418     TCU_CHECK_INTERNAL(memoryInfo);
419 
420     // Get memory info from activity manager:
421     // activityManager.getMemoryInfo(memoryInfo);
422     const jmethodID getMemoryInfoID =
423         getMethodID(env, activityManagerClass, "getMemoryInfo", "(Landroid/app/ActivityManager$MemoryInfo;)V");
424     checkException(env);
425     env->CallVoidMethod(*activityManager, getMemoryInfoID, *memoryInfo);
426 
427     // Return 'totalMem' field from the memory info instance.
428     return static_cast<size_t>(getField<int64_t>(env, *memoryInfo, "totalMem"));
429 }
430 
431 } // namespace Android
432 } // namespace tcu
433