15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/android/jni_android.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/android/build_info.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/android/jni_string.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::GetClass; 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::MethodID; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::ScopedJavaLocalRef; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JavaVM* g_jvm = NULL; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Leak the global app context, as it is used from a non-joinable worker thread 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that may still be running at shutdown. There is no harm in doing this. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_application_context = LAZY_INSTANCE_INITIALIZER; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jclass> throwable_clazz = 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetClass(env, "java/lang/Throwable"); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID throwable_printstacktrace = 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MethodID::Get<MethodID::TYPE_INSTANCE>( 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, throwable_clazz.obj(), "printStackTrace", 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "(Ljava/io/PrintStream;)V"); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an instance of ByteArrayOutputStream. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz = 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetClass(env, "java/io/ByteArrayOutputStream"); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID bytearray_output_stream_constructor = 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MethodID::Get<MethodID::TYPE_INSTANCE>( 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, bytearray_output_stream_clazz.obj(), "<init>", "()V"); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID bytearray_output_stream_tostring = 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MethodID::Get<MethodID::TYPE_INSTANCE>( 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, bytearray_output_stream_clazz.obj(), "toString", 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "()Ljava/lang/String;"); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jobject> bytearray_output_stream(env, 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->NewObject(bytearray_output_stream_clazz.obj(), 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytearray_output_stream_constructor)); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an instance of PrintStream. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jclass> printstream_clazz = 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetClass(env, "java/io/PrintStream"); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID printstream_constructor = 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MethodID::Get<MethodID::TYPE_INSTANCE>( 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, printstream_clazz.obj(), "<init>", 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "(Ljava/io/OutputStream;)V"); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jobject> printstream(env, 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->NewObject(printstream_clazz.obj(), printstream_constructor, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytearray_output_stream.obj())); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Call Throwable.printStackTrace(PrintStream) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->CallVoidMethod(java_throwable, throwable_printstacktrace, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printstream.obj()); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Call ByteArrayOutputStream.toString() 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jstring> exception_string( 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, static_cast<jstring>( 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->CallObjectMethod(bytearray_output_stream.obj(), 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytearray_output_stream_tostring))); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ConvertJavaStringToUTF8(exception_string); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace android { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JNIEnv* AttachCurrentThread() { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(g_jvm); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env = NULL; 7931fc3ed1513c41bdd4a09cdd402f3c4f53b0cecdTorne (Richard Coles) jint ret = g_jvm->AttachCurrentThread(&env, NULL); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(JNI_OK, ret); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return env; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DetachFromVM() { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore the return value, if the thread is not attached, DetachCurrentThread 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will fail. But it is ok as the native thread may never be attached. 8731fc3ed1513c41bdd4a09cdd402f3c4f53b0cecdTorne (Richard Coles) if (g_jvm) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_jvm->DetachCurrentThread(); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InitVM(JavaVM* vm) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!g_jvm); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_jvm = vm; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool IsVMInitialized() { 973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return g_jvm != NULL; 983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) { 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (env->IsSameObject(g_application_context.Get().obj(), context.obj())) { 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // It's safe to set the context more than once if it's the same context. 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(g_application_context.Get().is_null()); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_application_context.Get().Reset(context); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const jobject GetApplicationContext() { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!g_application_context.Get().is_null()); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return g_application_context.Get().obj(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jclass clazz = env->FindClass(class_name); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name; 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return ScopedJavaLocalRef<jclass>(env, clazz); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<MethodID::Type type> 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)jmethodID MethodID::Get(JNIEnv* env, 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jclass clazz, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* method_name, 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID id = type == TYPE_STATIC ? 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->GetStaticMethodID(clazz, method_name, jni_signature) : 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->GetMethodID(clazz, method_name, jni_signature); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(base::android::ClearException(env) || id) << 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to find " << 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (type == TYPE_STATIC ? "static " : "") << 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "method " << method_name << " " << jni_signature; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return id; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If |atomic_method_id| set, it'll return immediately. Otherwise, it'll call 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// into ::Get() above. If there's a race, it's ok since the values are the same 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (and the duplicated effort will happen only once). 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<MethodID::Type type> 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)jmethodID MethodID::LazyGet(JNIEnv* env, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jclass clazz, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* method_name, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature, 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::subtle::AtomicWord* atomic_method_id) { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID), 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AtomicWord_SmallerThan_jMethodID); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reinterpret_cast<jmethodID>(value); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID id = MethodID::Get<type>(env, clazz, method_name, jni_signature); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::subtle::Release_Store( 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) atomic_method_id, reinterpret_cast<subtle::AtomicWord>(id)); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return id; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Various template instantiations. 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template jmethodID MethodID::Get<MethodID::TYPE_STATIC>( 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env, jclass clazz, const char* method_name, 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template jmethodID MethodID::Get<MethodID::TYPE_INSTANCE>( 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env, jclass clazz, const char* method_name, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>( 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env, jclass clazz, const char* method_name, 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>( 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env, jclass clazz, const char* method_name, 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasException(JNIEnv* env) { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return env->ExceptionCheck() != JNI_FALSE; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ClearException(JNIEnv* env) { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HasException(env)) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->ExceptionDescribe(); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->ExceptionClear(); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CheckException(JNIEnv* env) { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HasException(env)) return; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Exception has been found, might as well tell breakpad about it. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jthrowable java_throwable = env->ExceptionOccurred(); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!java_throwable) { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do nothing but return false. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(false); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clear the pending exception, since a local reference is now held. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->ExceptionDescribe(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->ExceptionClear(); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the exception_string in BuildInfo so that breakpad can read it. 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RVO should avoid any extra copies of the exception string. 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::android::BuildInfo::GetInstance()->set_java_exception_info( 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetJavaExceptionInfo(env, java_throwable)); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now, feel good about it and die. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(false); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace android 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 209