• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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