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