OSDN Git Service

671cc20440c0b6247af5d2b24c09ec9297bdef79
[android-x86/frameworks-base.git] / core / jni / android_view_ThreadedRenderer.cpp
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 #include <atomic>
21
22 #include "jni.h"
23 #include <nativehelper/JNIHelp.h>
24 #include "core_jni_helpers.h"
25 #include <GraphicsJNI.h>
26 #include <nativehelper/ScopedPrimitiveArray.h>
27
28 #include <gui/BufferItemConsumer.h>
29 #include <gui/BufferQueue.h>
30 #include <gui/Surface.h>
31
32 #include <EGL/egl.h>
33 #include <EGL/eglext.h>
34 #include <private/EGL/cache.h>
35
36 #include <utils/Looper.h>
37 #include <utils/RefBase.h>
38 #include <utils/StrongPointer.h>
39 #include <utils/Timers.h>
40 #include <android_runtime/android_view_Surface.h>
41 #include <system/window.h>
42
43 #include "android_os_MessageQueue.h"
44
45 #include <Animator.h>
46 #include <AnimationContext.h>
47 #include <FrameInfo.h>
48 #include <FrameMetricsObserver.h>
49 #include <IContextFactory.h>
50 #include <Properties.h>
51 #include <PropertyValuesAnimatorSet.h>
52 #include <RenderNode.h>
53 #include <renderthread/CanvasContext.h>
54 #include <renderthread/RenderProxy.h>
55 #include <renderthread/RenderTask.h>
56 #include <renderthread/RenderThread.h>
57
58 namespace android {
59
60 using namespace android::uirenderer;
61 using namespace android::uirenderer::renderthread;
62
63 struct {
64     jfieldID frameMetrics;
65     jfieldID timingDataBuffer;
66     jfieldID messageQueue;
67     jmethodID callback;
68 } gFrameMetricsObserverClassInfo;
69
70 static JNIEnv* getenv(JavaVM* vm) {
71     JNIEnv* env;
72     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
73         LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
74     }
75     return env;
76 }
77
78 class OnFinishedEvent {
79 public:
80     OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
81             : animator(animator), listener(listener) {}
82     sp<BaseRenderNodeAnimator> animator;
83     sp<AnimationListener> listener;
84 };
85
86 class InvokeAnimationListeners : public MessageHandler {
87 public:
88     explicit InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) {
89         mOnFinishedEvents.swap(events);
90     }
91
92     static void callOnFinished(OnFinishedEvent& event) {
93         event.listener->onAnimationFinished(event.animator.get());
94     }
95
96     virtual void handleMessage(const Message& message) {
97         std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished);
98         mOnFinishedEvents.clear();
99     }
100
101 private:
102     std::vector<OnFinishedEvent> mOnFinishedEvents;
103 };
104
105 class FinishAndInvokeListener : public MessageHandler {
106 public:
107     explicit FinishAndInvokeListener(PropertyValuesAnimatorSet* anim)
108             : mAnimator(anim) {
109         mListener = anim->getOneShotListener();
110         mRequestId = anim->getRequestId();
111     }
112
113     virtual void handleMessage(const Message& message) {
114         if (mAnimator->getRequestId() == mRequestId) {
115             // Request Id has not changed, meaning there's no animation lifecyle change since the
116             // message is posted, so go ahead and call finish to make sure the PlayState is properly
117             // updated. This is needed because before the next frame comes in from UI thread to
118             // trigger an animation update, there could be reverse/cancel etc. So we need to update
119             // the playstate in time to ensure all the subsequent events get chained properly.
120             mAnimator->end();
121         }
122         mListener->onAnimationFinished(nullptr);
123     }
124 private:
125     sp<PropertyValuesAnimatorSet> mAnimator;
126     sp<AnimationListener> mListener;
127     uint32_t mRequestId;
128 };
129
130 class RenderingException : public MessageHandler {
131 public:
132     RenderingException(JavaVM* vm, const std::string& message)
133             : mVm(vm)
134             , mMessage(message) {
135     }
136
137     virtual void handleMessage(const Message&) {
138         throwException(mVm, mMessage);
139     }
140
141     static void throwException(JavaVM* vm, const std::string& message) {
142         JNIEnv* env = getenv(vm);
143         jniThrowException(env, "java/lang/IllegalStateException", message.c_str());
144     }
145
146 private:
147     JavaVM* mVm;
148     std::string mMessage;
149 };
150
151 class RootRenderNode : public RenderNode, ErrorHandler {
152 public:
153     explicit RootRenderNode(JNIEnv* env) : RenderNode() {
154         mLooper = Looper::getForThread();
155         LOG_ALWAYS_FATAL_IF(!mLooper.get(),
156                 "Must create RootRenderNode on a thread with a looper!");
157         env->GetJavaVM(&mVm);
158     }
159
160     virtual ~RootRenderNode() {}
161
162     virtual void onError(const std::string& message) override {
163         mLooper->sendMessage(new RenderingException(mVm, message), 0);
164     }
165
166     virtual void prepareTree(TreeInfo& info) override {
167         info.errorHandler = this;
168
169         for (auto& anim : mRunningVDAnimators) {
170             // Assume that the property change in VD from the animators will not be consumed. Mark
171             // otherwise if the VDs are found in the display list tree. For VDs that are not in
172             // the display list tree, we stop providing animation pulses by 1) removing them from
173             // the animation list, 2) post a delayed message to end them at end time so their
174             // listeners can receive the corresponding callbacks.
175             anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false);
176             // Mark the VD dirty so it will damage itself during prepareTree.
177             anim->getVectorDrawable()->markDirty();
178         }
179         if (info.mode == TreeInfo::MODE_FULL) {
180             for (auto &anim : mPausedVDAnimators) {
181                 anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false);
182                 anim->getVectorDrawable()->markDirty();
183             }
184         }
185         // TODO: This is hacky
186         info.updateWindowPositions = true;
187         RenderNode::prepareTree(info);
188         info.updateWindowPositions = false;
189         info.errorHandler = nullptr;
190     }
191
192     void sendMessage(const sp<MessageHandler>& handler) {
193         mLooper->sendMessage(handler, 0);
194     }
195
196     void sendMessageDelayed(const sp<MessageHandler>& handler, nsecs_t delayInMs) {
197         mLooper->sendMessageDelayed(ms2ns(delayInMs), handler, 0);
198     }
199
200     void attachAnimatingNode(RenderNode* animatingNode) {
201         mPendingAnimatingRenderNodes.push_back(animatingNode);
202     }
203
204     void attachPendingVectorDrawableAnimators() {
205         mRunningVDAnimators.insert(mPendingVectorDrawableAnimators.begin(),
206                 mPendingVectorDrawableAnimators.end());
207         mPendingVectorDrawableAnimators.clear();
208     }
209
210     void detachAnimators() {
211         // Remove animators from the list and post a delayed message in future to end the animator
212         // For infinite animators, remove the listener so we no longer hold a global ref to the AVD
213         // java object, and therefore the AVD objects in both native and Java can be properly
214         // released.
215         for (auto& anim : mRunningVDAnimators) {
216             detachVectorDrawableAnimator(anim.get());
217             anim->clearOneShotListener();
218         }
219         for (auto& anim : mPausedVDAnimators) {
220             anim->clearOneShotListener();
221         }
222         mRunningVDAnimators.clear();
223         mPausedVDAnimators.clear();
224     }
225
226     // Move all the animators to the paused list, and send a delayed message to notify the finished
227     // listener.
228     void pauseAnimators() {
229         mPausedVDAnimators.insert(mRunningVDAnimators.begin(), mRunningVDAnimators.end());
230         for (auto& anim : mRunningVDAnimators) {
231             detachVectorDrawableAnimator(anim.get());
232         }
233         mRunningVDAnimators.clear();
234     }
235
236     void doAttachAnimatingNodes(AnimationContext* context) {
237         for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) {
238             RenderNode* node = mPendingAnimatingRenderNodes[i].get();
239             context->addAnimatingRenderNode(*node);
240         }
241         mPendingAnimatingRenderNodes.clear();
242     }
243
244     // Run VectorDrawable animators after prepareTree.
245     void runVectorDrawableAnimators(AnimationContext* context, TreeInfo& info) {
246         // Push staging.
247         if (info.mode == TreeInfo::MODE_FULL) {
248             pushStagingVectorDrawableAnimators(context);
249         }
250
251         // Run the animators in the running list.
252         for (auto it = mRunningVDAnimators.begin(); it != mRunningVDAnimators.end();) {
253             if ((*it)->animate(*context)) {
254                 it = mRunningVDAnimators.erase(it);
255             } else {
256                 it++;
257             }
258         }
259
260         // Run the animators in paused list during full sync.
261         if (info.mode == TreeInfo::MODE_FULL) {
262             // During full sync we also need to pulse paused animators, in case their targets
263             // have been added back to the display list. All the animators that passed the
264             // scheduled finish time will be removed from the paused list.
265             for (auto it = mPausedVDAnimators.begin(); it != mPausedVDAnimators.end();) {
266                 if ((*it)->animate(*context)) {
267                     // Animator has finished, remove from the list.
268                     it = mPausedVDAnimators.erase(it);
269                 } else {
270                     it++;
271                 }
272             }
273         }
274
275         // Move the animators with a target not in DisplayList to paused list.
276         for (auto it = mRunningVDAnimators.begin(); it != mRunningVDAnimators.end();) {
277             if (!(*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) {
278                 // Vector Drawable is not in the display list, we should remove this animator from
279                 // the list, put it in the paused list, and post a delayed message to end the
280                 // animator.
281                 detachVectorDrawableAnimator(it->get());
282                 mPausedVDAnimators.insert(*it);
283                 it = mRunningVDAnimators.erase(it);
284             } else {
285                 it++;
286             }
287         }
288
289         // Move the animators with a target in DisplayList from paused list to running list, and
290         // trim paused list.
291         if (info.mode == TreeInfo::MODE_FULL) {
292             // Check whether any paused animator's target is back in Display List. If so, put the
293             // animator back in the running list.
294             for (auto it = mPausedVDAnimators.begin(); it != mPausedVDAnimators.end();) {
295                 if ((*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) {
296                     mRunningVDAnimators.insert(*it);
297                     it = mPausedVDAnimators.erase(it);
298                 } else {
299                     it++;
300                 }
301             }
302             // Trim paused VD animators at full sync, so that when Java loses reference to an
303             // animator, we know we won't be requested to animate it any more, then we remove such
304             // animators from the paused list so they can be properly freed. We also remove the
305             // animators from paused list when the time elapsed since start has exceeded duration.
306             trimPausedVDAnimators(context);
307         }
308
309         info.out.hasAnimations |= !mRunningVDAnimators.empty();
310     }
311
312     void trimPausedVDAnimators(AnimationContext* context) {
313         // Trim paused vector drawable animator list.
314         for (auto it = mPausedVDAnimators.begin(); it != mPausedVDAnimators.end();) {
315             // Remove paused VD animator if no one else is referencing it. Note that animators that
316             // have passed scheduled finish time are removed from list when they are being pulsed
317             // before prepare tree.
318             // TODO: this is a bit hacky, need to figure out a better way to track when the paused
319             // animators should be freed.
320             if ((*it)->getStrongCount() == 1) {
321                 it = mPausedVDAnimators.erase(it);
322             } else {
323                 it++;
324             }
325         }
326     }
327
328     void pushStagingVectorDrawableAnimators(AnimationContext* context) {
329         for (auto& anim : mRunningVDAnimators) {
330             anim->pushStaging(*context);
331         }
332     }
333
334     void destroy() {
335         for (auto& renderNode : mPendingAnimatingRenderNodes) {
336             renderNode->animators().endAllStagingAnimators();
337         }
338         mPendingAnimatingRenderNodes.clear();
339         mPendingVectorDrawableAnimators.clear();
340     }
341
342     void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) {
343         mPendingVectorDrawableAnimators.insert(anim);
344     }
345
346 private:
347     sp<Looper> mLooper;
348     JavaVM* mVm;
349     std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
350     std::set< sp<PropertyValuesAnimatorSet> > mPendingVectorDrawableAnimators;
351     std::set< sp<PropertyValuesAnimatorSet> > mRunningVDAnimators;
352     // mPausedVDAnimators stores a list of animators that have not yet passed the finish time, but
353     // their VectorDrawable targets are no longer in the DisplayList. We skip these animators when
354     // render thread runs animators independent of UI thread (i.e. RT_ONLY mode). These animators
355     // need to be re-activated once their VD target is added back into DisplayList. Since that could
356     // only happen when we do a full sync, we need to make sure to pulse these paused animators at
357     // full sync. If any animator's VD target is found in DisplayList during a full sync, we move
358     // the animator back to the running list.
359     std::set< sp<PropertyValuesAnimatorSet> > mPausedVDAnimators;
360     void detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) {
361         if (anim->isInfinite() || !anim->isRunning()) {
362             // Do not need to post anything if the animation is infinite (i.e. no meaningful
363             // end listener action), or if the animation has already ended.
364             return;
365         }
366         nsecs_t remainingTimeInMs = anim->getRemainingPlayTime();
367         // Post a delayed onFinished event that is scheduled to be handled when the animator ends.
368         if (anim->getOneShotListener()) {
369             // VectorDrawable's oneshot listener is updated when there are user triggered animation
370             // lifecycle changes, such as start(), end(), etc. By using checking and clearing
371             // one shot listener, we ensure the same end listener event gets posted only once.
372             // Therefore no duplicates. Another benefit of using one shot listener is that no
373             // removal is necessary: the end time of animation will not change unless triggered by
374             // user events, in which case the already posted listener's id will become stale, and
375             // the onFinished callback will then be ignored.
376             sp<FinishAndInvokeListener> message
377                     = new FinishAndInvokeListener(anim);
378             sendMessageDelayed(message, remainingTimeInMs);
379             anim->clearOneShotListener();
380         }
381     }
382 };
383
384 class AnimationContextBridge : public AnimationContext {
385 public:
386     AnimationContextBridge(renderthread::TimeLord& clock, RootRenderNode* rootNode)
387             : AnimationContext(clock), mRootNode(rootNode) {
388     }
389
390     virtual ~AnimationContextBridge() {}
391
392     // Marks the start of a frame, which will update the frame time and move all
393     // next frame animations into the current frame
394     virtual void startFrame(TreeInfo::TraversalMode mode) {
395         if (mode == TreeInfo::MODE_FULL) {
396             mRootNode->doAttachAnimatingNodes(this);
397             mRootNode->attachPendingVectorDrawableAnimators();
398         }
399         AnimationContext::startFrame(mode);
400     }
401
402     // Runs any animations still left in mCurrentFrameAnimations
403     virtual void runRemainingAnimations(TreeInfo& info) {
404         AnimationContext::runRemainingAnimations(info);
405         mRootNode->runVectorDrawableAnimators(this, info);
406         postOnFinishedEvents();
407     }
408
409     virtual void pauseAnimators() override {
410         mRootNode->pauseAnimators();
411     }
412
413     virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
414         OnFinishedEvent event(animator, listener);
415         mOnFinishedEvents.push_back(event);
416     }
417
418     virtual void destroy() {
419         AnimationContext::destroy();
420         mRootNode->detachAnimators();
421         postOnFinishedEvents();
422     }
423
424 private:
425     sp<RootRenderNode> mRootNode;
426     std::vector<OnFinishedEvent> mOnFinishedEvents;
427
428     void postOnFinishedEvents() {
429         if (mOnFinishedEvents.size()) {
430             sp<InvokeAnimationListeners> message
431                     = new InvokeAnimationListeners(mOnFinishedEvents);
432             mRootNode->sendMessage(message);
433         }
434     }
435 };
436
437 class ContextFactoryImpl : public IContextFactory {
438 public:
439     explicit ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {}
440
441     virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
442         return new AnimationContextBridge(clock, mRootNode);
443     }
444
445 private:
446     RootRenderNode* mRootNode;
447 };
448
449 class ObserverProxy;
450
451 class NotifyHandler : public MessageHandler {
452 public:
453     NotifyHandler(JavaVM* vm, ObserverProxy* observer) : mVm(vm), mObserver(observer) {}
454
455     virtual void handleMessage(const Message& message);
456
457 private:
458     JavaVM* const mVm;
459     ObserverProxy* const mObserver;
460 };
461
462 static jlongArray get_metrics_buffer(JNIEnv* env, jobject observer) {
463     jobject frameMetrics = env->GetObjectField(
464             observer, gFrameMetricsObserverClassInfo.frameMetrics);
465     LOG_ALWAYS_FATAL_IF(frameMetrics == nullptr, "unable to retrieve data sink object");
466     jobject buffer = env->GetObjectField(
467             frameMetrics, gFrameMetricsObserverClassInfo.timingDataBuffer);
468     LOG_ALWAYS_FATAL_IF(buffer == nullptr, "unable to retrieve data sink buffer");
469     return reinterpret_cast<jlongArray>(buffer);
470 }
471
472 /*
473  * Implements JNI layer for hwui frame metrics reporting.
474  */
475 class ObserverProxy : public FrameMetricsObserver {
476 public:
477     ObserverProxy(JavaVM *vm, jobject observer) : mVm(vm) {
478         JNIEnv* env = getenv(mVm);
479
480         mObserverWeak = env->NewWeakGlobalRef(observer);
481         LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr,
482                 "unable to create frame stats observer reference");
483
484         jlongArray buffer = get_metrics_buffer(env, observer);
485         jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(buffer));
486         LOG_ALWAYS_FATAL_IF(bufferSize != kBufferSize,
487                 "Mismatched Java/Native FrameMetrics data format.");
488
489         jobject messageQueueLocal = env->GetObjectField(
490                 observer, gFrameMetricsObserverClassInfo.messageQueue);
491         mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal);
492         LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available");
493
494         mMessageHandler = new NotifyHandler(mVm, this);
495         LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr,
496                 "OOM: unable to allocate NotifyHandler");
497     }
498
499     ~ObserverProxy() {
500         JNIEnv* env = getenv(mVm);
501         env->DeleteWeakGlobalRef(mObserverWeak);
502     }
503
504     jweak getObserverReference() {
505         return mObserverWeak;
506     }
507
508     bool getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) {
509         FrameMetricsNotification& elem = mRingBuffer[mNextInQueue];
510
511         if (elem.hasData.load()) {
512             env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer);
513             *dropCount = elem.dropCount;
514             mNextInQueue = (mNextInQueue + 1) % kRingSize;
515             elem.hasData = false;
516             return true;
517         }
518
519         return false;
520     }
521
522     virtual void notify(const int64_t* stats) {
523         FrameMetricsNotification& elem = mRingBuffer[mNextFree];
524
525         if (!elem.hasData.load()) {
526             memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0]));
527
528             elem.dropCount = mDroppedReports;
529             mDroppedReports = 0;
530
531             incStrong(nullptr);
532             mNextFree = (mNextFree + 1) % kRingSize;
533             elem.hasData = true;
534
535             mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage);
536         } else {
537             mDroppedReports++;
538         }
539     }
540
541 private:
542     static const int kBufferSize = static_cast<int>(FrameInfoIndex::NumIndexes);
543     static constexpr int kRingSize = 3;
544
545     class FrameMetricsNotification {
546     public:
547         FrameMetricsNotification() : hasData(false) {}
548
549         std::atomic_bool hasData;
550         int64_t buffer[kBufferSize];
551         int dropCount = 0;
552     };
553
554     JavaVM* const mVm;
555     jweak mObserverWeak;
556
557     sp<MessageQueue> mMessageQueue;
558     sp<NotifyHandler> mMessageHandler;
559     Message mMessage;
560
561     int mNextFree = 0;
562     int mNextInQueue = 0;
563     FrameMetricsNotification mRingBuffer[kRingSize];
564
565     int mDroppedReports = 0;
566 };
567
568 void NotifyHandler::handleMessage(const Message& message) {
569     JNIEnv* env = getenv(mVm);
570
571     jobject target = env->NewLocalRef(mObserver->getObserverReference());
572
573     if (target != nullptr) {
574         jlongArray javaBuffer = get_metrics_buffer(env, target);
575         int dropCount = 0;
576         while (mObserver->getNextBuffer(env, javaBuffer, &dropCount)) {
577             env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback, dropCount);
578         }
579         env->DeleteLocalRef(target);
580     }
581
582     mObserver->decStrong(nullptr);
583 }
584
585 static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) {
586     RenderProxy::rotateProcessStatsBuffer();
587 }
588
589 static void android_view_ThreadedRenderer_setProcessStatsBuffer(JNIEnv* env, jobject clazz,
590         jint fd) {
591     RenderProxy::setProcessStatsBuffer(fd);
592 }
593
594 static jint android_view_ThreadedRenderer_getRenderThreadTid(JNIEnv* env, jobject clazz,
595         jlong proxyPtr) {
596     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
597     return proxy->getRenderThreadTid();
598 }
599
600 static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
601     RootRenderNode* node = new RootRenderNode(env);
602     node->incStrong(0);
603     node->setName("RootRenderNode");
604     return reinterpret_cast<jlong>(node);
605 }
606
607 static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
608         jboolean translucent, jlong rootRenderNodePtr) {
609     RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
610     ContextFactoryImpl factory(rootRenderNode);
611     return (jlong) new RenderProxy(translucent, rootRenderNode, &factory);
612 }
613
614 static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
615         jlong proxyPtr) {
616     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
617     delete proxy;
618 }
619
620 static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
621         jlong proxyPtr) {
622     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
623     return proxy->loadSystemProperties();
624 }
625
626 static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz,
627         jlong proxyPtr, jstring jname) {
628     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
629     const char* name = env->GetStringUTFChars(jname, NULL);
630     proxy->setName(name);
631     env->ReleaseStringUTFChars(jname, name);
632 }
633
634 static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
635         jlong proxyPtr, jobject jsurface) {
636     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
637     sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
638     proxy->initialize(surface);
639 }
640
641 static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
642         jlong proxyPtr, jobject jsurface) {
643     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
644     sp<Surface> surface;
645     if (jsurface) {
646         surface = android_view_Surface_getSurface(env, jsurface);
647     }
648     proxy->updateSurface(surface);
649 }
650
651 static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
652         jlong proxyPtr, jobject jsurface) {
653     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
654     sp<Surface> surface;
655     if (jsurface) {
656         surface = android_view_Surface_getSurface(env, jsurface);
657     }
658     return proxy->pauseSurface(surface);
659 }
660
661 static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz,
662         jlong proxyPtr, jboolean stopped) {
663     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
664     proxy->setStopped(stopped);
665 }
666
667 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
668         jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) {
669     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
670     proxy->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha);
671 }
672
673 static void android_view_ThreadedRenderer_setLightCenter(JNIEnv* env, jobject clazz,
674         jlong proxyPtr, jfloat lightX, jfloat lightY, jfloat lightZ) {
675     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
676     proxy->setLightCenter((Vector3){lightX, lightY, lightZ});
677 }
678
679 static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
680         jlong proxyPtr, jboolean opaque) {
681     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
682     proxy->setOpaque(opaque);
683 }
684
685 static void android_view_ThreadedRenderer_setWideGamut(JNIEnv* env, jobject clazz,
686         jlong proxyPtr, jboolean wideGamut) {
687     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
688     proxy->setWideGamut(wideGamut);
689 }
690
691 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
692         jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
693     LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
694             "Mismatched size expectations, given %d expected %d",
695             frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
696     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
697     env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
698     return proxy->syncAndDrawFrame();
699 }
700
701 static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
702         jlong proxyPtr, jlong rootNodePtr) {
703     RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
704     rootRenderNode->destroy();
705     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
706     proxy->destroy();
707 }
708
709 static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,
710         jlong rootNodePtr, jlong animatingNodePtr) {
711     RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
712     RenderNode* animatingNode = reinterpret_cast<RenderNode*>(animatingNodePtr);
713     rootRenderNode->attachAnimatingNode(animatingNode);
714 }
715
716 static void android_view_ThreadedRenderer_registerVectorDrawableAnimator(JNIEnv* env, jobject clazz,
717         jlong rootNodePtr, jlong animatorPtr) {
718     RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
719     PropertyValuesAnimatorSet* animator = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr);
720     rootRenderNode->addVectorDrawableAnimator(animator);
721 }
722
723 static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
724         jlong functorPtr, jboolean waitForCompletion) {
725     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
726     RenderProxy::invokeFunctor(functor, waitForCompletion);
727 }
728
729 static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
730         jlong proxyPtr) {
731     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
732     DeferredLayerUpdater* layer = proxy->createTextureLayer();
733     return reinterpret_cast<jlong>(layer);
734 }
735
736 static void android_view_ThreadedRenderer_buildLayer(JNIEnv* env, jobject clazz,
737         jlong proxyPtr, jlong nodePtr) {
738     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
739     RenderNode* node = reinterpret_cast<RenderNode*>(nodePtr);
740     proxy->buildLayer(node);
741 }
742
743 static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
744         jlong proxyPtr, jlong layerPtr, jobject jbitmap) {
745     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
746     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
747     SkBitmap bitmap;
748     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
749     return proxy->copyLayerInto(layer, bitmap);
750 }
751
752 static void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz,
753         jlong proxyPtr, jlong layerPtr) {
754     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
755     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
756     proxy->pushLayerUpdate(layer);
757 }
758
759 static void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz,
760         jlong proxyPtr, jlong layerPtr) {
761     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
762     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
763     proxy->cancelLayerUpdate(layer);
764 }
765
766 static void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobject clazz,
767         jlong proxyPtr, jlong layerPtr) {
768     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
769     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
770     proxy->detachSurfaceTexture(layer);
771 }
772
773 static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
774         jlong proxyPtr) {
775     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
776     proxy->destroyHardwareResources();
777 }
778
779 static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
780         jint level) {
781     RenderProxy::trimMemory(level);
782 }
783
784 static void android_view_ThreadedRenderer_overrideProperty(JNIEnv* env, jobject clazz,
785         jstring name, jstring value) {
786     const char* nameCharArray = env->GetStringUTFChars(name, NULL);
787     const char* valueCharArray = env->GetStringUTFChars(value, NULL);
788     RenderProxy::overrideProperty(nameCharArray, valueCharArray);
789     env->ReleaseStringUTFChars(name, nameCharArray);
790     env->ReleaseStringUTFChars(name, valueCharArray);
791 }
792
793 static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
794         jlong proxyPtr) {
795     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
796     proxy->fence();
797 }
798
799 static void android_view_ThreadedRenderer_stopDrawing(JNIEnv* env, jobject clazz,
800         jlong proxyPtr) {
801     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
802     proxy->stopDrawing();
803 }
804
805 static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
806         jlong proxyPtr) {
807     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
808     proxy->notifyFramePending();
809 }
810
811 static void android_view_ThreadedRenderer_serializeDisplayListTree(JNIEnv* env, jobject clazz,
812         jlong proxyPtr) {
813     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
814     proxy->serializeDisplayListTree();
815 }
816
817 static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
818         jlong proxyPtr, jobject javaFileDescriptor, jint dumpFlags) {
819     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
820     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
821     proxy->dumpProfileInfo(fd, dumpFlags);
822 }
823
824 static void android_view_ThreadedRenderer_addRenderNode(JNIEnv* env, jobject clazz,
825         jlong proxyPtr, jlong renderNodePtr, jboolean placeFront) {
826     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
827     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
828     proxy->addRenderNode(renderNode, placeFront);
829 }
830
831 static void android_view_ThreadedRenderer_removeRenderNode(JNIEnv* env, jobject clazz,
832         jlong proxyPtr, jlong renderNodePtr) {
833     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
834     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
835     proxy->removeRenderNode(renderNode);
836 }
837
838 static void android_view_ThreadedRendererd_drawRenderNode(JNIEnv* env, jobject clazz,
839         jlong proxyPtr, jlong renderNodePtr) {
840     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
841     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
842     proxy->drawRenderNode(renderNode);
843 }
844
845 static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env,
846         jobject clazz, jlong proxyPtr, jint left, jint top, jint right, jint bottom) {
847     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
848     proxy->setContentDrawBounds(left, top, right, bottom);
849 }
850
851 static jint android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
852         jobject clazz, jobject jsurface, jint left, jint top,
853         jint right, jint bottom, jobject jbitmap) {
854     SkBitmap bitmap;
855     GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
856     sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
857     return RenderProxy::copySurfaceInto(surface, left, top, right, bottom, &bitmap);
858 }
859
860 class ContextFactory : public IContextFactory {
861 public:
862     virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
863         return new AnimationContext(clock);
864     }
865 };
866
867 static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode(JNIEnv* env,
868         jobject clazz, jlong renderNodePtr, jint jwidth, jint jheight) {
869     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
870     if (jwidth <= 0 || jheight <= 0) {
871         ALOGW("Invalid width %d or height %d", jwidth, jheight);
872         return nullptr;
873     }
874
875     uint32_t width = jwidth;
876     uint32_t height = jheight;
877
878     // Create a Surface wired up to a BufferItemConsumer
879     sp<IGraphicBufferProducer> producer;
880     sp<IGraphicBufferConsumer> rawConsumer;
881     BufferQueue::createBufferQueue(&producer, &rawConsumer);
882     // We only need 1 buffer but some drivers have bugs so workaround it by setting max count to 2
883     rawConsumer->setMaxBufferCount(2);
884     sp<BufferItemConsumer> consumer = new BufferItemConsumer(rawConsumer,
885             GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER);
886     consumer->setDefaultBufferSize(width, height);
887     sp<Surface> surface = new Surface(producer);
888
889     // Render into the surface
890     {
891         ContextFactory factory;
892         RenderProxy proxy{true, renderNode, &factory};
893         proxy.loadSystemProperties();
894         proxy.setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
895         proxy.initialize(surface);
896         // Shadows can't be used via this interface, so just set the light source
897         // to all 0s.
898         proxy.setup(0, 0, 0);
899         proxy.setLightCenter((Vector3){0, 0, 0});
900         nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
901         UiFrameInfoBuilder(proxy.frameInfo())
902                 .setVsync(vsync, vsync)
903                 .addFlag(FrameInfoFlags::SurfaceCanvas);
904         proxy.syncAndDrawFrame();
905     }
906
907     // Yank out the GraphicBuffer
908     BufferItem bufferItem;
909     status_t err;
910     if ((err = consumer->acquireBuffer(&bufferItem, 0, true)) != OK) {
911         ALOGW("Failed to acquireBuffer, error %d (%s)", err, strerror(-err));
912         return nullptr;
913     }
914     sp<GraphicBuffer> buffer = bufferItem.mGraphicBuffer;
915     // We don't really care if this fails or not since we're just going to destroy this anyway
916     consumer->releaseBuffer(bufferItem);
917     if (!buffer.get()) {
918         ALOGW("GraphicBuffer is null?");
919         return nullptr;
920     }
921     if (buffer->getWidth() != width || buffer->getHeight() != height) {
922         ALOGW("GraphicBuffer size mismatch, got %dx%d expected %dx%d",
923                 buffer->getWidth(), buffer->getHeight(), width, height);
924         // Continue I guess?
925     }
926     sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
927     return createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_Mutable);
928 }
929
930 static void android_view_ThreadedRenderer_disableVsync(JNIEnv*, jclass) {
931     RenderProxy::disableVsync();
932 }
933
934
935 static void android_view_ThreadedRenderer_hackySetRTAnimationsEnabled(JNIEnv*, jclass,
936         jboolean enable) {
937     Properties::enableRTAnimations = enable;
938 }
939
940 // ----------------------------------------------------------------------------
941 // FrameMetricsObserver
942 // ----------------------------------------------------------------------------
943
944 static jlong android_view_ThreadedRenderer_addFrameMetricsObserver(JNIEnv* env,
945         jclass clazz, jlong proxyPtr, jobject fso) {
946     JavaVM* vm = nullptr;
947     if (env->GetJavaVM(&vm) != JNI_OK) {
948         LOG_ALWAYS_FATAL("Unable to get Java VM");
949         return 0;
950     }
951
952     renderthread::RenderProxy* renderProxy =
953             reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
954
955     FrameMetricsObserver* observer = new ObserverProxy(vm, fso);
956     renderProxy->addFrameMetricsObserver(observer);
957     return reinterpret_cast<jlong>(observer);
958 }
959
960 static void android_view_ThreadedRenderer_removeFrameMetricsObserver(JNIEnv* env, jclass clazz,
961         jlong proxyPtr, jlong observerPtr) {
962     FrameMetricsObserver* observer = reinterpret_cast<FrameMetricsObserver*>(observerPtr);
963     renderthread::RenderProxy* renderProxy =
964             reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
965
966     renderProxy->removeFrameMetricsObserver(observer);
967 }
968
969 // ----------------------------------------------------------------------------
970 // Shaders
971 // ----------------------------------------------------------------------------
972
973 static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
974         jstring diskCachePath) {
975     const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
976     android::egl_set_cache_filename(cacheArray);
977     env->ReleaseStringUTFChars(diskCachePath, cacheArray);
978 }
979
980 // ----------------------------------------------------------------------------
981 // JNI Glue
982 // ----------------------------------------------------------------------------
983
984 const char* const kClassPathName = "android/view/ThreadedRenderer";
985
986 static const JNINativeMethod gMethods[] = {
987     { "nRotateProcessStatsBuffer", "()V", (void*) android_view_ThreadedRenderer_rotateProcessStatsBuffer },
988     { "nSetProcessStatsBuffer", "(I)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
989     { "nGetRenderThreadTid", "(J)I", (void*) android_view_ThreadedRenderer_getRenderThreadTid },
990     { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
991     { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
992     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
993     { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
994     { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
995     { "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize },
996     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
997     { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
998     { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped },
999     { "nSetup", "(JFII)V", (void*) android_view_ThreadedRenderer_setup },
1000     { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
1001     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
1002     { "nSetWideGamut", "(JZ)V", (void*) android_view_ThreadedRenderer_setWideGamut },
1003     { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
1004     { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
1005     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
1006     { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator },
1007     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
1008     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
1009     { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
1010     { "nCopyLayerInto", "(JJLandroid/graphics/Bitmap;)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
1011     { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
1012     { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
1013     { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
1014     { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources },
1015     { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory },
1016     { "nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V",  (void*) android_view_ThreadedRenderer_overrideProperty },
1017     { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
1018     { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
1019     { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
1020     { "nSerializeDisplayListTree", "(J)V", (void*) android_view_ThreadedRenderer_serializeDisplayListTree },
1021     { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
1022     { "setupShadersDiskCache", "(Ljava/lang/String;)V",
1023                 (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
1024     { "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode},
1025     { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
1026     { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
1027     { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
1028     { "nAddFrameMetricsObserver",
1029             "(JLandroid/view/FrameMetricsObserver;)J",
1030             (void*)android_view_ThreadedRenderer_addFrameMetricsObserver },
1031     { "nRemoveFrameMetricsObserver",
1032             "(JJ)V",
1033             (void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
1034     { "nCopySurfaceInto", "(Landroid/view/Surface;IIIILandroid/graphics/Bitmap;)I",
1035                 (void*)android_view_ThreadedRenderer_copySurfaceInto },
1036     { "nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;",
1037             (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode },
1038     { "disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync },
1039     { "nHackySetRTAnimationsEnabled", "(Z)V",
1040             (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled },
1041 };
1042
1043 int register_android_view_ThreadedRenderer(JNIEnv* env) {
1044     jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver");
1045     gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie(
1046             env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;");
1047     gFrameMetricsObserverClassInfo.messageQueue = GetFieldIDOrDie(
1048             env, observerClass, "mMessageQueue", "Landroid/os/MessageQueue;");
1049     gFrameMetricsObserverClassInfo.callback = GetMethodIDOrDie(
1050             env, observerClass, "notifyDataAvailable", "(I)V");
1051
1052     jclass metricsClass = FindClassOrDie(env, "android/view/FrameMetrics");
1053     gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie(
1054             env, metricsClass, "mTimingData", "[J");
1055
1056     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1057 }
1058
1059 }; // namespace android