Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "ThreadedRenderer"
     18 
     19 #include <algorithm>
     20 
     21 #include "jni.h"
     22 #include <nativehelper/JNIHelp.h>
     23 #include "core_jni_helpers.h"
     24 #include <GraphicsJNI.h>
     25 #include <ScopedPrimitiveArray.h>
     26 
     27 #include <EGL/egl.h>
     28 #include <EGL/eglext.h>
     29 #include <EGL/egl_cache.h>
     30 
     31 #include <utils/StrongPointer.h>
     32 #include <android_runtime/android_view_Surface.h>
     33 #include <system/window.h>
     34 
     35 #include "android_view_GraphicBuffer.h"
     36 
     37 #include <Animator.h>
     38 #include <AnimationContext.h>
     39 #include <IContextFactory.h>
     40 #include <JankTracker.h>
     41 #include <RenderNode.h>
     42 #include <renderthread/CanvasContext.h>
     43 #include <renderthread/RenderProxy.h>
     44 #include <renderthread/RenderTask.h>
     45 #include <renderthread/RenderThread.h>
     46 #include <Vector.h>
     47 
     48 namespace android {
     49 
     50 using namespace android::uirenderer;
     51 using namespace android::uirenderer::renderthread;
     52 
     53 static JNIEnv* getenv(JavaVM* vm) {
     54     JNIEnv* env;
     55     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
     56         LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
     57     }
     58     return env;
     59 }
     60 
     61 class OnFinishedEvent {
     62 public:
     63     OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
     64             : animator(animator), listener(listener) {}
     65     sp<BaseRenderNodeAnimator> animator;
     66     sp<AnimationListener> listener;
     67 };
     68 
     69 class InvokeAnimationListeners : public MessageHandler {
     70 public:
     71     InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) {
     72         mOnFinishedEvents.swap(events);
     73     }
     74 
     75     static void callOnFinished(OnFinishedEvent& event) {
     76         event.listener->onAnimationFinished(event.animator.get());
     77     }
     78 
     79     virtual void handleMessage(const Message& message) {
     80         std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished);
     81         mOnFinishedEvents.clear();
     82     }
     83 
     84 private:
     85     std::vector<OnFinishedEvent> mOnFinishedEvents;
     86 };
     87 
     88 class RenderingException : public MessageHandler {
     89 public:
     90     RenderingException(JavaVM* vm, const std::string& message)
     91             : mVm(vm)
     92             , mMessage(message) {
     93     }
     94 
     95     virtual void handleMessage(const Message&) {
     96         throwException(mVm, mMessage);
     97     }
     98 
     99     static void throwException(JavaVM* vm, const std::string& message) {
    100         JNIEnv* env = getenv(vm);
    101         jniThrowException(env, "java/lang/IllegalStateException", message.c_str());
    102     }
    103 
    104 private:
    105     JavaVM* mVm;
    106     std::string mMessage;
    107 };
    108 
    109 class RootRenderNode : public RenderNode, ErrorHandler {
    110 public:
    111     RootRenderNode(JNIEnv* env) : RenderNode() {
    112         mLooper = Looper::getForThread();
    113         LOG_ALWAYS_FATAL_IF(!mLooper.get(),
    114                 "Must create RootRenderNode on a thread with a looper!");
    115         env->GetJavaVM(&mVm);
    116     }
    117 
    118     virtual ~RootRenderNode() {}
    119 
    120     virtual void onError(const std::string& message) {
    121         mLooper->sendMessage(new RenderingException(mVm, message), 0);
    122     }
    123 
    124     virtual void prepareTree(TreeInfo& info) {
    125         info.errorHandler = this;
    126         RenderNode::prepareTree(info);
    127         info.errorHandler = NULL;
    128     }
    129 
    130     void sendMessage(const sp<MessageHandler>& handler) {
    131         mLooper->sendMessage(handler, 0);
    132     }
    133 
    134     void attachAnimatingNode(RenderNode* animatingNode) {
    135         mPendingAnimatingRenderNodes.push_back(animatingNode);
    136     }
    137 
    138     void doAttachAnimatingNodes(AnimationContext* context) {
    139         for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) {
    140             RenderNode* node = mPendingAnimatingRenderNodes[i].get();
    141             context->addAnimatingRenderNode(*node);
    142         }
    143         mPendingAnimatingRenderNodes.clear();
    144     }
    145 
    146 private:
    147     sp<Looper> mLooper;
    148     JavaVM* mVm;
    149     std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
    150 };
    151 
    152 class AnimationContextBridge : public AnimationContext {
    153 public:
    154     AnimationContextBridge(renderthread::TimeLord& clock, RootRenderNode* rootNode)
    155             : AnimationContext(clock), mRootNode(rootNode) {
    156     }
    157 
    158     virtual ~AnimationContextBridge() {}
    159 
    160     // Marks the start of a frame, which will update the frame time and move all
    161     // next frame animations into the current frame
    162     virtual void startFrame(TreeInfo::TraversalMode mode) {
    163         if (mode == TreeInfo::MODE_FULL) {
    164             mRootNode->doAttachAnimatingNodes(this);
    165         }
    166         AnimationContext::startFrame(mode);
    167     }
    168 
    169     // Runs any animations still left in mCurrentFrameAnimations
    170     virtual void runRemainingAnimations(TreeInfo& info) {
    171         AnimationContext::runRemainingAnimations(info);
    172         postOnFinishedEvents();
    173     }
    174 
    175     virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
    176         OnFinishedEvent event(animator, listener);
    177         mOnFinishedEvents.push_back(event);
    178     }
    179 
    180     virtual void destroy() {
    181         AnimationContext::destroy();
    182         postOnFinishedEvents();
    183     }
    184 
    185 private:
    186     sp<RootRenderNode> mRootNode;
    187     std::vector<OnFinishedEvent> mOnFinishedEvents;
    188 
    189     void postOnFinishedEvents() {
    190         if (mOnFinishedEvents.size()) {
    191             sp<InvokeAnimationListeners> message
    192                     = new InvokeAnimationListeners(mOnFinishedEvents);
    193             mRootNode->sendMessage(message);
    194         }
    195     }
    196 };
    197 
    198 class ContextFactoryImpl : public IContextFactory {
    199 public:
    200     ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {}
    201 
    202     virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
    203         return new AnimationContextBridge(clock, mRootNode);
    204     }
    205 
    206 private:
    207     RootRenderNode* mRootNode;
    208 };
    209 
    210 static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
    211         jlong proxyPtr, jobject graphicBuffer, jlongArray atlasMapArray) {
    212     sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
    213     jsize len = env->GetArrayLength(atlasMapArray);
    214     if (len <= 0) {
    215         ALOGW("Failed to initialize atlas, invalid map length: %d", len);
    216         return;
    217     }
    218     int64_t* map = new int64_t[len];
    219     env->GetLongArrayRegion(atlasMapArray, 0, len, map);
    220 
    221     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    222     proxy->setTextureAtlas(buffer, map, len);
    223 }
    224 
    225 static void android_view_ThreadedRenderer_setProcessStatsBuffer(JNIEnv* env, jobject clazz,
    226         jlong proxyPtr, jint fd) {
    227     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    228     proxy->setProcessStatsBuffer(fd);
    229 }
    230 
    231 static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
    232     RootRenderNode* node = new RootRenderNode(env);
    233     node->incStrong(0);
    234     node->setName("RootRenderNode");
    235     return reinterpret_cast<jlong>(node);
    236 }
    237 
    238 static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
    239         jboolean translucent, jlong rootRenderNodePtr) {
    240     RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
    241     ContextFactoryImpl factory(rootRenderNode);
    242     return (jlong) new RenderProxy(translucent, rootRenderNode, &factory);
    243 }
    244 
    245 static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
    246         jlong proxyPtr) {
    247     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    248     delete proxy;
    249 }
    250 
    251 static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
    252         jlong proxyPtr) {
    253     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    254     return proxy->loadSystemProperties();
    255 }
    256 
    257 static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz,
    258         jlong proxyPtr, jstring jname) {
    259     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    260     const char* name = env->GetStringUTFChars(jname, NULL);
    261     proxy->setName(name);
    262     env->ReleaseStringUTFChars(jname, name);
    263 }
    264 
    265 static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
    266         jlong proxyPtr, jobject jsurface) {
    267     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    268     sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
    269     return proxy->initialize(window);
    270 }
    271 
    272 static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
    273         jlong proxyPtr, jobject jsurface) {
    274     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    275     sp<ANativeWindow> window;
    276     if (jsurface) {
    277         window = android_view_Surface_getNativeWindow(env, jsurface);
    278     }
    279     proxy->updateSurface(window);
    280 }
    281 
    282 static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
    283         jlong proxyPtr, jobject jsurface) {
    284     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    285     sp<ANativeWindow> window;
    286     if (jsurface) {
    287         window = android_view_Surface_getNativeWindow(env, jsurface);
    288     }
    289     return proxy->pauseSurface(window);
    290 }
    291 
    292 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
    293         jint width, jint height, jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) {
    294     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    295     proxy->setup(width, height, lightRadius, ambientShadowAlpha, spotShadowAlpha);
    296 }
    297 
    298 static void android_view_ThreadedRenderer_setLightCenter(JNIEnv* env, jobject clazz,
    299         jlong proxyPtr, jfloat lightX, jfloat lightY, jfloat lightZ) {
    300     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    301     proxy->setLightCenter((Vector3){lightX, lightY, lightZ});
    302 }
    303 
    304 static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
    305         jlong proxyPtr, jboolean opaque) {
    306     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    307     proxy->setOpaque(opaque);
    308 }
    309 
    310 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
    311         jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
    312     LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
    313             "Mismatched size expectations, given %d expected %d",
    314             frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
    315     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    316     env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
    317     return proxy->syncAndDrawFrame();
    318 }
    319 
    320 static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
    321         jlong proxyPtr) {
    322     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    323     proxy->destroy();
    324 }
    325 
    326 static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,
    327         jlong rootNodePtr, jlong animatingNodePtr) {
    328     RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
    329     RenderNode* animatingNode = reinterpret_cast<RenderNode*>(animatingNodePtr);
    330     rootRenderNode->attachAnimatingNode(animatingNode);
    331 }
    332 
    333 static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
    334         jlong functorPtr, jboolean waitForCompletion) {
    335     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
    336     RenderProxy::invokeFunctor(functor, waitForCompletion);
    337 }
    338 
    339 static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
    340         jlong proxyPtr) {
    341     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    342     DeferredLayerUpdater* layer = proxy->createTextureLayer();
    343     return reinterpret_cast<jlong>(layer);
    344 }
    345 
    346 static void android_view_ThreadedRenderer_buildLayer(JNIEnv* env, jobject clazz,
    347         jlong proxyPtr, jlong nodePtr) {
    348     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    349     RenderNode* node = reinterpret_cast<RenderNode*>(nodePtr);
    350     proxy->buildLayer(node);
    351 }
    352 
    353 static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
    354         jlong proxyPtr, jlong layerPtr, jobject jbitmap) {
    355     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    356     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
    357     SkBitmap bitmap;
    358     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
    359     return proxy->copyLayerInto(layer, bitmap);
    360 }
    361 
    362 static void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz,
    363         jlong proxyPtr, jlong layerPtr) {
    364     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    365     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
    366     proxy->pushLayerUpdate(layer);
    367 }
    368 
    369 static void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz,
    370         jlong proxyPtr, jlong layerPtr) {
    371     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    372     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
    373     proxy->cancelLayerUpdate(layer);
    374 }
    375 
    376 static void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobject clazz,
    377         jlong proxyPtr, jlong layerPtr) {
    378     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    379     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
    380     proxy->detachSurfaceTexture(layer);
    381 }
    382 
    383 static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
    384         jlong proxyPtr) {
    385     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    386     proxy->destroyHardwareResources();
    387 }
    388 
    389 static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
    390         jint level) {
    391     RenderProxy::trimMemory(level);
    392 }
    393 
    394 static void android_view_ThreadedRenderer_overrideProperty(JNIEnv* env, jobject clazz,
    395         jstring name, jstring value) {
    396     const char* nameCharArray = env->GetStringUTFChars(name, NULL);
    397     const char* valueCharArray = env->GetStringUTFChars(value, NULL);
    398     RenderProxy::overrideProperty(nameCharArray, valueCharArray);
    399     env->ReleaseStringUTFChars(name, nameCharArray);
    400     env->ReleaseStringUTFChars(name, valueCharArray);
    401 }
    402 
    403 static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
    404         jlong proxyPtr) {
    405     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    406     proxy->fence();
    407 }
    408 
    409 static void android_view_ThreadedRenderer_stopDrawing(JNIEnv* env, jobject clazz,
    410         jlong proxyPtr) {
    411     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    412     proxy->stopDrawing();
    413 }
    414 
    415 static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
    416         jlong proxyPtr) {
    417     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    418     proxy->notifyFramePending();
    419 }
    420 
    421 static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
    422         jlong proxyPtr, jobject javaFileDescriptor, jint dumpFlags) {
    423     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
    424     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
    425     proxy->dumpProfileInfo(fd, dumpFlags);
    426 }
    427 
    428 static void android_view_ThreadedRenderer_dumpProfileData(JNIEnv* env, jobject clazz,
    429         jbyteArray jdata, jobject javaFileDescriptor) {
    430     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
    431     ScopedByteArrayRO buffer(env, jdata);
    432     if (buffer.get()) {
    433         JankTracker::dumpBuffer(buffer.get(), buffer.size(), fd);
    434     }
    435 }
    436 
    437 
    438 // ----------------------------------------------------------------------------
    439 // Shaders
    440 // ----------------------------------------------------------------------------
    441 
    442 static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
    443         jstring diskCachePath) {
    444 
    445     const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
    446     egl_cache_t::get()->setCacheFilename(cacheArray);
    447     env->ReleaseStringUTFChars(diskCachePath, cacheArray);
    448 }
    449 
    450 // ----------------------------------------------------------------------------
    451 // JNI Glue
    452 // ----------------------------------------------------------------------------
    453 
    454 const char* const kClassPathName = "android/view/ThreadedRenderer";
    455 
    456 static JNINativeMethod gMethods[] = {
    457     { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
    458     { "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
    459     { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
    460     { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
    461     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
    462     { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
    463     { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
    464     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
    465     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
    466     { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
    467     { "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
    468     { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
    469     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
    470     { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
    471     { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
    472     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
    473     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
    474     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
    475     { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
    476     { "nCopyLayerInto", "(JJLandroid/graphics/Bitmap;)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
    477     { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
    478     { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
    479     { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
    480     { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources },
    481     { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory },
    482     { "nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V",  (void*) android_view_ThreadedRenderer_overrideProperty },
    483     { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
    484     { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
    485     { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
    486     { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
    487     { "nDumpProfileData", "([BLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileData },
    488     { "setupShadersDiskCache", "(Ljava/lang/String;)V",
    489                 (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
    490 };
    491 
    492 int register_android_view_ThreadedRenderer(JNIEnv* env) {
    493     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
    494 }
    495 
    496 }; // namespace android
    497