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 31namespace tcu 32{ 33namespace Android 34{ 35 36using std::string; 37using std::vector; 38 39namespace 40{ 41 42class ScopedJNIEnv 43{ 44public: 45 46 ScopedJNIEnv (JavaVM* vm); 47 ~ScopedJNIEnv (void); 48 49 JavaVM* getVM (void) const { return m_vm; } 50 JNIEnv* getEnv (void) const { return m_env; } 51 52private: 53 JavaVM* const m_vm; 54 JNIEnv* m_env; 55 bool m_detach; 56}; 57 58ScopedJNIEnv::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 78ScopedJNIEnv::~ScopedJNIEnv (void) 79{ 80 if (m_detach) 81 m_vm->DetachCurrentThread(); 82} 83 84class LocalRef 85{ 86public: 87 LocalRef (JNIEnv* env, jobject ref); 88 ~LocalRef (void); 89 90 jobject operator* (void) const { return m_ref; } 91 operator bool (void) const { return !!m_ref; } 92 93private: 94 LocalRef (const LocalRef&); 95 LocalRef& operator= (const LocalRef&); 96 97 JNIEnv* const m_env; 98 const jobject m_ref; 99}; 100 101LocalRef::LocalRef (JNIEnv* env, jobject ref) 102 : m_env(env) 103 , m_ref(ref) 104{ 105} 106 107LocalRef::~LocalRef (void) 108{ 109 if (m_ref) 110 m_env->DeleteLocalRef(m_ref); 111} 112 113void 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 123jclass 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 133jclass 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 143jmethodID 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 153string 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 163string 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 186void 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 194template<typename Type> 195const char* getJNITypeStr (void); 196 197template<> 198const char* getJNITypeStr<int> (void) 199{ 200 return "I"; 201} 202 203template<> 204const char* getJNITypeStr<deInt64> (void) 205{ 206 return "J"; 207} 208 209template<> 210const char* getJNITypeStr<string> (void) 211{ 212 return "Ljava/lang/String;"; 213} 214 215template<> 216const char* getJNITypeStr<vector<string> > (void) 217{ 218 return "[Ljava/lang/String;"; 219} 220 221template<typename FieldType> 222FieldType getStaticFieldValue (JNIEnv* env, jclass cls, jfieldID fieldId); 223 224template<> 225int getStaticFieldValue<int> (JNIEnv* env, jclass cls, jfieldID fieldId) 226{ 227 DE_ASSERT(cls && fieldId); 228 return env->GetStaticIntField(cls, fieldId); 229} 230 231template<> 232string 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 242template<> 243vector<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 268template<typename FieldType> 269FieldType 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 282template<typename FieldType> 283FieldType getFieldValue (JNIEnv* env, jobject obj, jfieldID fieldId); 284 285template<> 286deInt64 getFieldValue<deInt64> (JNIEnv* env, jobject obj, jfieldID fieldId) 287{ 288 DE_ASSERT(obj && fieldId); 289 return env->GetLongField(obj, fieldId); 290} 291 292template<typename FieldType> 293FieldType 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 306void 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 353ScreenOrientation 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 368string getIntentStringExtra (ANativeActivity* activity, const char* name) 369{ 370 const ScopedJNIEnv env(activity->vm); 371 372 return getIntentStringExtra(env.getEnv(), activity->clazz, name); 373} 374 375void setRequestedOrientation (ANativeActivity* activity, ScreenOrientation orientation) 376{ 377 const ScopedJNIEnv env(activity->vm); 378 379 setRequestedOrientation(env.getEnv(), activity->clazz, orientation); 380} 381 382void describePlatform (ANativeActivity* activity, std::ostream& dst) 383{ 384 const ScopedJNIEnv env(activity->vm); 385 386 describePlatform(env.getEnv(), dst); 387} 388 389size_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