1 /*
2  * Copyright (C) 2013 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 "SurfaceControl"
18 #define LOG_NDEBUG 0
19 
20 #include "android_os_Parcel.h"
21 #include "android_util_Binder.h"
22 #include "android/graphics/Bitmap.h"
23 #include "android/graphics/GraphicsJNI.h"
24 #include "android/graphics/Region.h"
25 #include "core_jni_helpers.h"
26 
27 #include <JNIHelp.h>
28 #include <ScopedUtfChars.h>
29 #include <android_runtime/android_view_Surface.h>
30 #include <android_runtime/android_view_SurfaceSession.h>
31 #include <gui/Surface.h>
32 #include <gui/SurfaceComposerClient.h>
33 #include <jni.h>
34 #include <memory>
35 #include <stdio.h>
36 #include <system/graphics.h>
37 #include <ui/DisplayInfo.h>
38 #include <ui/HdrCapabilities.h>
39 #include <ui/FrameStats.h>
40 #include <ui/Rect.h>
41 #include <ui/Region.h>
42 #include <utils/Log.h>
43 
44 // ----------------------------------------------------------------------------
45 
46 namespace android {
47 
48 static const char* const OutOfResourcesException =
49     "android/view/Surface$OutOfResourcesException";
50 
51 static struct {
52     jclass clazz;
53     jmethodID ctor;
54     jfieldID width;
55     jfieldID height;
56     jfieldID refreshRate;
57     jfieldID density;
58     jfieldID xDpi;
59     jfieldID yDpi;
60     jfieldID secure;
61     jfieldID appVsyncOffsetNanos;
62     jfieldID presentationDeadlineNanos;
63 } gPhysicalDisplayInfoClassInfo;
64 
65 static struct {
66     jfieldID bottom;
67     jfieldID left;
68     jfieldID right;
69     jfieldID top;
70 } gRectClassInfo;
71 
72 // Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
DeleteScreenshot(void * addr,void * context)73 void DeleteScreenshot(void* addr, void* context) {
74     SkASSERT(addr == ((ScreenshotClient*) context)->getPixels());
75     delete ((ScreenshotClient*) context);
76 }
77 
78 static struct {
79     nsecs_t UNDEFINED_TIME_NANO;
80     jmethodID init;
81 } gWindowContentFrameStatsClassInfo;
82 
83 static struct {
84     nsecs_t UNDEFINED_TIME_NANO;
85     jmethodID init;
86 } gWindowAnimationFrameStatsClassInfo;
87 
88 static struct {
89     jclass clazz;
90     jmethodID ctor;
91 } gHdrCapabilitiesClassInfo;
92 
93 static struct {
94     jclass clazz;
95     jmethodID builder;
96 } gGraphicBufferClassInfo;
97 
98 // ----------------------------------------------------------------------------
99 
nativeCreate(JNIEnv * env,jclass clazz,jobject sessionObj,jstring nameStr,jint w,jint h,jint format,jint flags,jlong parentObject,jint windowType,jint ownerUid)100 static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
101         jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
102         jint windowType, jint ownerUid) {
103     ScopedUtfChars name(env, nameStr);
104     sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
105     SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
106     sp<SurfaceControl> surface = client->createSurface(
107             String8(name.c_str()), w, h, format, flags, parent, windowType, ownerUid);
108     if (surface == NULL) {
109         jniThrowException(env, OutOfResourcesException, NULL);
110         return 0;
111     }
112 
113     surface->incStrong((void *)nativeCreate);
114     return reinterpret_cast<jlong>(surface.get());
115 }
116 
nativeRelease(JNIEnv * env,jclass clazz,jlong nativeObject)117 static void nativeRelease(JNIEnv* env, jclass clazz, jlong nativeObject) {
118     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
119     ctrl->decStrong((void *)nativeCreate);
120 }
121 
nativeDestroy(JNIEnv * env,jclass clazz,jlong nativeObject)122 static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) {
123     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
124     ctrl->clear();
125     ctrl->decStrong((void *)nativeCreate);
126 }
127 
nativeDisconnect(JNIEnv * env,jclass clazz,jlong nativeObject)128 static void nativeDisconnect(JNIEnv* env, jclass clazz, jlong nativeObject) {
129     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
130     if (ctrl != NULL) {
131         ctrl->disconnect();
132     }
133 }
134 
rectFromObj(JNIEnv * env,jobject rectObj)135 static Rect rectFromObj(JNIEnv* env, jobject rectObj) {
136     int left = env->GetIntField(rectObj, gRectClassInfo.left);
137     int top = env->GetIntField(rectObj, gRectClassInfo.top);
138     int right = env->GetIntField(rectObj, gRectClassInfo.right);
139     int bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
140     return Rect(left, top, right, bottom);
141 }
142 
nativeScreenshotToBuffer(JNIEnv * env,jclass clazz,jobject displayTokenObj,jobject sourceCropObj,jint width,jint height,jint minLayer,jint maxLayer,bool allLayers,bool useIdentityTransform,int rotation)143 static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz,
144         jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
145         jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
146         int rotation) {
147     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
148     if (displayToken == NULL) {
149         return NULL;
150     }
151     Rect sourceCrop = rectFromObj(env, sourceCropObj);
152     if (allLayers) {
153         minLayer = INT32_MIN;
154         maxLayer = INT32_MAX;
155     }
156     sp<GraphicBuffer> buffer;
157     status_t res = ScreenshotClient::captureToBuffer(displayToken,
158             sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform,
159             rotation, &buffer);
160     if (res != NO_ERROR) {
161         return NULL;
162     }
163 
164     return env->CallStaticObjectMethod(gGraphicBufferClassInfo.clazz,
165             gGraphicBufferClassInfo.builder,
166             buffer->getWidth(),
167             buffer->getHeight(),
168             buffer->getPixelFormat(),
169             buffer->getUsage(),
170             (jlong)buffer.get());
171 }
172 
nativeScreenshotBitmap(JNIEnv * env,jclass clazz,jobject displayTokenObj,jobject sourceCropObj,jint width,jint height,jint minLayer,jint maxLayer,bool allLayers,bool useIdentityTransform,int rotation)173 static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
174         jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
175         jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
176         int rotation) {
177     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
178     if (displayToken == NULL) {
179         return NULL;
180     }
181 
182     Rect sourceCrop = rectFromObj(env, sourceCropObj);
183 
184     std::unique_ptr<ScreenshotClient> screenshot(new ScreenshotClient());
185     status_t res;
186     if (allLayers) {
187         minLayer = INT32_MIN;
188         maxLayer = INT32_MAX;
189     }
190 
191     res = screenshot->update(displayToken, sourceCrop, width, height,
192         minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation));
193     if (res != NO_ERROR) {
194         return NULL;
195     }
196 
197     SkColorType colorType;
198     SkAlphaType alphaType;
199     switch (screenshot->getFormat()) {
200         case PIXEL_FORMAT_RGBX_8888: {
201             colorType = kRGBA_8888_SkColorType;
202             alphaType = kOpaque_SkAlphaType;
203             break;
204         }
205         case PIXEL_FORMAT_RGBA_8888: {
206             colorType = kRGBA_8888_SkColorType;
207             alphaType = kPremul_SkAlphaType;
208             break;
209         }
210         case PIXEL_FORMAT_RGBA_FP16: {
211             colorType = kRGBA_F16_SkColorType;
212             alphaType = kPremul_SkAlphaType;
213             break;
214         }
215         case PIXEL_FORMAT_RGB_565: {
216             colorType = kRGB_565_SkColorType;
217             alphaType = kOpaque_SkAlphaType;
218             break;
219         }
220         default: {
221             return NULL;
222         }
223     }
224     SkImageInfo screenshotInfo = SkImageInfo::Make(screenshot->getWidth(),
225                                                    screenshot->getHeight(),
226                                                    colorType,
227                                                    alphaType,
228                                                    GraphicsJNI::defaultColorSpace());
229 
230     const size_t rowBytes =
231             screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());
232 
233     if (!screenshotInfo.width() || !screenshotInfo.height()) {
234         return NULL;
235     }
236 
237     auto bitmap = new Bitmap(
238             (void*) screenshot->getPixels(), (void*) screenshot.get(), DeleteScreenshot,
239             screenshotInfo, rowBytes, nullptr);
240     screenshot.release();
241     bitmap->setImmutable();
242     return bitmap::createBitmap(env, bitmap,
243             android::bitmap::kBitmapCreateFlag_Premultiplied, NULL);
244 }
245 
nativeScreenshot(JNIEnv * env,jclass clazz,jobject displayTokenObj,jobject surfaceObj,jobject sourceCropObj,jint width,jint height,jint minLayer,jint maxLayer,bool allLayers,bool useIdentityTransform)246 static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
247         jobject surfaceObj, jobject sourceCropObj, jint width, jint height,
248         jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) {
249     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
250     if (displayToken != NULL) {
251         sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
252         if (consumer != NULL) {
253             int left = env->GetIntField(sourceCropObj, gRectClassInfo.left);
254             int top = env->GetIntField(sourceCropObj, gRectClassInfo.top);
255             int right = env->GetIntField(sourceCropObj, gRectClassInfo.right);
256             int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom);
257             Rect sourceCrop(left, top, right, bottom);
258 
259             if (allLayers) {
260                 minLayer = INT32_MIN;
261                 maxLayer = INT32_MAX;
262             }
263             ScreenshotClient::capture(displayToken,
264                     consumer->getIGraphicBufferProducer(), sourceCrop,
265                     width, height, minLayer, maxLayer,
266                     useIdentityTransform);
267         }
268     }
269 }
270 
nativeOpenTransaction(JNIEnv * env,jclass clazz)271 static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
272     SurfaceComposerClient::openGlobalTransaction();
273 }
274 
275 
nativeCloseTransaction(JNIEnv * env,jclass clazz,jboolean sync)276 static void nativeCloseTransaction(JNIEnv* env, jclass clazz, jboolean sync) {
277     SurfaceComposerClient::closeGlobalTransaction(sync);
278 }
279 
nativeSetAnimationTransaction(JNIEnv * env,jclass clazz)280 static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
281     SurfaceComposerClient::setAnimationTransaction();
282 }
283 
nativeSetLayer(JNIEnv * env,jclass clazz,jlong nativeObject,jint zorder)284 static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong nativeObject, jint zorder) {
285     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
286     status_t err = ctrl->setLayer(zorder);
287     if (err < 0 && err != NO_INIT) {
288         doThrowIAE(env);
289     }
290 }
291 
nativeSetRelativeLayer(JNIEnv * env,jclass clazz,jlong nativeObject,jobject relativeTo,jint zorder)292 static void nativeSetRelativeLayer(JNIEnv* env, jclass clazz, jlong nativeObject,
293         jobject relativeTo, jint zorder) {
294     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
295     sp<IBinder> handle = ibinderForJavaObject(env, relativeTo);
296 
297     ctrl->setRelativeLayer(handle, zorder);
298 }
299 
nativeSetPosition(JNIEnv * env,jclass clazz,jlong nativeObject,jfloat x,jfloat y)300 static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat x, jfloat y) {
301     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
302     status_t err = ctrl->setPosition(x, y);
303     if (err < 0 && err != NO_INIT) {
304         doThrowIAE(env);
305     }
306 }
307 
nativeSetGeometryAppliesWithResize(JNIEnv * env,jclass clazz,jlong nativeObject)308 static void nativeSetGeometryAppliesWithResize(JNIEnv* env, jclass clazz,
309         jlong nativeObject) {
310     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
311     status_t err = ctrl->setGeometryAppliesWithResize();
312     if (err < 0 && err != NO_INIT) {
313         doThrowIAE(env);
314     }
315 }
316 
nativeSetSize(JNIEnv * env,jclass clazz,jlong nativeObject,jint w,jint h)317 static void nativeSetSize(JNIEnv* env, jclass clazz, jlong nativeObject, jint w, jint h) {
318     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
319     status_t err = ctrl->setSize(w, h);
320     if (err < 0 && err != NO_INIT) {
321         doThrowIAE(env);
322     }
323 }
324 
nativeSetFlags(JNIEnv * env,jclass clazz,jlong nativeObject,jint flags,jint mask)325 static void nativeSetFlags(JNIEnv* env, jclass clazz, jlong nativeObject, jint flags, jint mask) {
326     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
327     status_t err = ctrl->setFlags(flags, mask);
328     if (err < 0 && err != NO_INIT) {
329         doThrowIAE(env);
330     }
331 }
332 
nativeSetTransparentRegionHint(JNIEnv * env,jclass clazz,jlong nativeObject,jobject regionObj)333 static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong nativeObject, jobject regionObj) {
334     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
335     SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
336     if (!region) {
337         doThrowIAE(env);
338         return;
339     }
340 
341     const SkIRect& b(region->getBounds());
342     Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
343     if (region->isComplex()) {
344         SkRegion::Iterator it(*region);
345         while (!it.done()) {
346             const SkIRect& r(it.rect());
347             reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
348             it.next();
349         }
350     }
351 
352     status_t err = ctrl->setTransparentRegionHint(reg);
353     if (err < 0 && err != NO_INIT) {
354         doThrowIAE(env);
355     }
356 }
357 
nativeSetAlpha(JNIEnv * env,jclass clazz,jlong nativeObject,jfloat alpha)358 static void nativeSetAlpha(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat alpha) {
359     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
360     status_t err = ctrl->setAlpha(alpha);
361     if (err < 0 && err != NO_INIT) {
362         doThrowIAE(env);
363     }
364 }
365 
nativeSetMatrix(JNIEnv * env,jclass clazz,jlong nativeObject,jfloat dsdx,jfloat dtdx,jfloat dtdy,jfloat dsdy)366 static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong nativeObject,
367         jfloat dsdx, jfloat dtdx, jfloat dtdy, jfloat dsdy) {
368     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
369     status_t err = ctrl->setMatrix(dsdx, dtdx, dtdy, dsdy);
370     if (err < 0 && err != NO_INIT) {
371         doThrowIAE(env);
372     }
373 }
374 
nativeSetWindowCrop(JNIEnv * env,jclass clazz,jlong nativeObject,jint l,jint t,jint r,jint b)375 static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jlong nativeObject,
376         jint l, jint t, jint r, jint b) {
377     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
378     Rect crop(l, t, r, b);
379     status_t err = ctrl->setCrop(crop);
380     if (err < 0 && err != NO_INIT) {
381         doThrowIAE(env);
382     }
383 }
384 
nativeSetFinalCrop(JNIEnv * env,jclass clazz,jlong nativeObject,jint l,jint t,jint r,jint b)385 static void nativeSetFinalCrop(JNIEnv* env, jclass clazz, jlong nativeObject,
386         jint l, jint t, jint r, jint b) {
387     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
388     Rect crop(l, t, r, b);
389     status_t err = ctrl->setFinalCrop(crop);
390     if (err < 0 && err != NO_INIT) {
391         doThrowIAE(env);
392     }
393 }
394 
nativeSetLayerStack(JNIEnv * env,jclass clazz,jlong nativeObject,jint layerStack)395 static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong nativeObject, jint layerStack) {
396     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
397     status_t err = ctrl->setLayerStack(layerStack);
398     if (err < 0 && err != NO_INIT) {
399         doThrowIAE(env);
400     }
401 }
402 
nativeGetBuiltInDisplay(JNIEnv * env,jclass clazz,jint id)403 static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
404     sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
405     return javaObjectForIBinder(env, token);
406 }
407 
nativeCreateDisplay(JNIEnv * env,jclass clazz,jstring nameObj,jboolean secure)408 static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
409         jboolean secure) {
410     ScopedUtfChars name(env, nameObj);
411     sp<IBinder> token(SurfaceComposerClient::createDisplay(
412             String8(name.c_str()), bool(secure)));
413     return javaObjectForIBinder(env, token);
414 }
415 
nativeDestroyDisplay(JNIEnv * env,jclass clazz,jobject tokenObj)416 static void nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
417     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
418     if (token == NULL) return;
419     SurfaceComposerClient::destroyDisplay(token);
420 }
421 
nativeSetDisplaySurface(JNIEnv * env,jclass clazz,jobject tokenObj,jlong nativeSurfaceObject)422 static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
423         jobject tokenObj, jlong nativeSurfaceObject) {
424     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
425     if (token == NULL) return;
426     sp<IGraphicBufferProducer> bufferProducer;
427     sp<Surface> sur(reinterpret_cast<Surface *>(nativeSurfaceObject));
428     if (sur != NULL) {
429         bufferProducer = sur->getIGraphicBufferProducer();
430     }
431     status_t err = SurfaceComposerClient::setDisplaySurface(token,
432             bufferProducer);
433     if (err != NO_ERROR) {
434         doThrowIAE(env, "Illegal Surface, could not enable async mode. Was this"
435                 " Surface created with singleBufferMode?");
436     }
437 }
438 
nativeSetDisplayLayerStack(JNIEnv * env,jclass clazz,jobject tokenObj,jint layerStack)439 static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
440         jobject tokenObj, jint layerStack) {
441     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
442     if (token == NULL) return;
443 
444     SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
445 }
446 
nativeSetDisplayProjection(JNIEnv * env,jclass clazz,jobject tokenObj,jint orientation,jint layerStackRect_left,jint layerStackRect_top,jint layerStackRect_right,jint layerStackRect_bottom,jint displayRect_left,jint displayRect_top,jint displayRect_right,jint displayRect_bottom)447 static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
448         jobject tokenObj, jint orientation,
449         jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
450         jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
451     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
452     if (token == NULL) return;
453     Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
454     Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
455     SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
456 }
457 
nativeSetDisplaySize(JNIEnv * env,jclass clazz,jobject tokenObj,jint width,jint height)458 static void nativeSetDisplaySize(JNIEnv* env, jclass clazz,
459         jobject tokenObj, jint width, jint height) {
460     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
461     if (token == NULL) return;
462     SurfaceComposerClient::setDisplaySize(token, width, height);
463 }
464 
nativeGetDisplayConfigs(JNIEnv * env,jclass clazz,jobject tokenObj)465 static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
466         jobject tokenObj) {
467     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
468     if (token == NULL) return NULL;
469 
470     Vector<DisplayInfo> configs;
471     if (SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
472             configs.size() == 0) {
473         return NULL;
474     }
475 
476     jobjectArray configArray = env->NewObjectArray(configs.size(),
477             gPhysicalDisplayInfoClassInfo.clazz, NULL);
478 
479     for (size_t c = 0; c < configs.size(); ++c) {
480         const DisplayInfo& info = configs[c];
481         jobject infoObj = env->NewObject(gPhysicalDisplayInfoClassInfo.clazz,
482                 gPhysicalDisplayInfoClassInfo.ctor);
483         env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
484         env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
485         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
486         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
487         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
488         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
489         env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
490         env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos,
491                 info.appVsyncOffset);
492         env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos,
493                 info.presentationDeadline);
494         env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
495         env->DeleteLocalRef(infoObj);
496     }
497 
498     return configArray;
499 }
500 
nativeGetActiveConfig(JNIEnv * env,jclass clazz,jobject tokenObj)501 static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
502     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
503     if (token == NULL) return -1;
504     return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
505 }
506 
nativeSetActiveConfig(JNIEnv * env,jclass clazz,jobject tokenObj,jint id)507 static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj, jint id) {
508     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
509     if (token == NULL) return JNI_FALSE;
510     status_t err = SurfaceComposerClient::setActiveConfig(token, static_cast<int>(id));
511     return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
512 }
513 
nativeGetDisplayColorModes(JNIEnv * env,jclass,jobject tokenObj)514 static jintArray nativeGetDisplayColorModes(JNIEnv* env, jclass, jobject tokenObj) {
515     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
516     if (token == NULL) return NULL;
517     Vector<android_color_mode_t> colorModes;
518     if (SurfaceComposerClient::getDisplayColorModes(token, &colorModes) != NO_ERROR ||
519             colorModes.isEmpty()) {
520         return NULL;
521     }
522 
523     jintArray colorModesArray = env->NewIntArray(colorModes.size());
524     if (colorModesArray == NULL) {
525         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
526         return NULL;
527     }
528     jint* colorModesArrayValues = env->GetIntArrayElements(colorModesArray, 0);
529     for (size_t i = 0; i < colorModes.size(); i++) {
530         colorModesArrayValues[i] = static_cast<jint>(colorModes[i]);
531     }
532     env->ReleaseIntArrayElements(colorModesArray, colorModesArrayValues, 0);
533     return colorModesArray;
534 }
535 
nativeGetActiveColorMode(JNIEnv * env,jclass,jobject tokenObj)536 static jint nativeGetActiveColorMode(JNIEnv* env, jclass, jobject tokenObj) {
537     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
538     if (token == NULL) return -1;
539     return static_cast<jint>(SurfaceComposerClient::getActiveColorMode(token));
540 }
541 
nativeSetActiveColorMode(JNIEnv * env,jclass,jobject tokenObj,jint colorMode)542 static jboolean nativeSetActiveColorMode(JNIEnv* env, jclass,
543         jobject tokenObj, jint colorMode) {
544     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
545     if (token == NULL) return JNI_FALSE;
546     status_t err = SurfaceComposerClient::setActiveColorMode(token,
547             static_cast<android_color_mode_t>(colorMode));
548     return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
549 }
550 
nativeSetDisplayPowerMode(JNIEnv * env,jclass clazz,jobject tokenObj,jint mode)551 static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) {
552     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
553     if (token == NULL) return;
554 
555     ALOGD_IF_SLOW(100, "Excessive delay in setPowerMode()");
556     SurfaceComposerClient::setDisplayPowerMode(token, mode);
557 }
558 
nativeClearContentFrameStats(JNIEnv * env,jclass clazz,jlong nativeObject)559 static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
560     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
561     status_t err = ctrl->clearLayerFrameStats();
562 
563     if (err < 0 && err != NO_INIT) {
564         doThrowIAE(env);
565     }
566 
567     // The other end is not ready, just report we failed.
568     if (err == NO_INIT) {
569         return JNI_FALSE;
570     }
571 
572     return JNI_TRUE;
573 }
574 
nativeGetContentFrameStats(JNIEnv * env,jclass clazz,jlong nativeObject,jobject outStats)575 static jboolean nativeGetContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject,
576     jobject outStats) {
577     FrameStats stats;
578 
579     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
580     status_t err = ctrl->getLayerFrameStats(&stats);
581     if (err < 0 && err != NO_INIT) {
582         doThrowIAE(env);
583     }
584 
585     // The other end is not ready, fine just return empty stats.
586     if (err == NO_INIT) {
587         return JNI_FALSE;
588     }
589 
590     jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
591     size_t frameCount = stats.desiredPresentTimesNano.size();
592 
593     jlongArray postedTimesNanoDst = env->NewLongArray(frameCount);
594     if (postedTimesNanoDst == NULL) {
595         return JNI_FALSE;
596     }
597 
598     jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
599     if (presentedTimesNanoDst == NULL) {
600         return JNI_FALSE;
601     }
602 
603     jlongArray readyTimesNanoDst = env->NewLongArray(frameCount);
604     if (readyTimesNanoDst == NULL) {
605         return JNI_FALSE;
606     }
607 
608     nsecs_t postedTimesNanoSrc[frameCount];
609     nsecs_t presentedTimesNanoSrc[frameCount];
610     nsecs_t readyTimesNanoSrc[frameCount];
611 
612     for (size_t i = 0; i < frameCount; i++) {
613         nsecs_t postedTimeNano = stats.desiredPresentTimesNano[i];
614         if (postedTimeNano == INT64_MAX) {
615             postedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
616         }
617         postedTimesNanoSrc[i] = postedTimeNano;
618 
619         nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
620         if (presentedTimeNano == INT64_MAX) {
621             presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
622         }
623         presentedTimesNanoSrc[i] = presentedTimeNano;
624 
625         nsecs_t readyTimeNano = stats.frameReadyTimesNano[i];
626         if (readyTimeNano == INT64_MAX) {
627             readyTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
628         }
629         readyTimesNanoSrc[i] = readyTimeNano;
630     }
631 
632     env->SetLongArrayRegion(postedTimesNanoDst, 0, frameCount, postedTimesNanoSrc);
633     env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
634     env->SetLongArrayRegion(readyTimesNanoDst, 0, frameCount, readyTimesNanoSrc);
635 
636     env->CallVoidMethod(outStats, gWindowContentFrameStatsClassInfo.init, refreshPeriodNano,
637             postedTimesNanoDst, presentedTimesNanoDst, readyTimesNanoDst);
638 
639     if (env->ExceptionCheck()) {
640         return JNI_FALSE;
641     }
642 
643     return JNI_TRUE;
644 }
645 
nativeClearAnimationFrameStats(JNIEnv * env,jclass clazz)646 static jboolean nativeClearAnimationFrameStats(JNIEnv* env, jclass clazz) {
647     status_t err = SurfaceComposerClient::clearAnimationFrameStats();
648 
649     if (err < 0 && err != NO_INIT) {
650         doThrowIAE(env);
651     }
652 
653     // The other end is not ready, just report we failed.
654     if (err == NO_INIT) {
655         return JNI_FALSE;
656     }
657 
658     return JNI_TRUE;
659 }
660 
nativeGetAnimationFrameStats(JNIEnv * env,jclass clazz,jobject outStats)661 static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject outStats) {
662     FrameStats stats;
663 
664     status_t err = SurfaceComposerClient::getAnimationFrameStats(&stats);
665     if (err < 0 && err != NO_INIT) {
666         doThrowIAE(env);
667     }
668 
669     // The other end is not ready, fine just return empty stats.
670     if (err == NO_INIT) {
671         return JNI_FALSE;
672     }
673 
674     jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
675     size_t frameCount = stats.desiredPresentTimesNano.size();
676 
677     jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
678     if (presentedTimesNanoDst == NULL) {
679         return JNI_FALSE;
680     }
681 
682     nsecs_t presentedTimesNanoSrc[frameCount];
683 
684     for (size_t i = 0; i < frameCount; i++) {
685         nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
686         if (presentedTimeNano == INT64_MAX) {
687             presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
688         }
689         presentedTimesNanoSrc[i] = presentedTimeNano;
690     }
691 
692     env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
693 
694     env->CallVoidMethod(outStats, gWindowAnimationFrameStatsClassInfo.init, refreshPeriodNano,
695             presentedTimesNanoDst);
696 
697     if (env->ExceptionCheck()) {
698         return JNI_FALSE;
699     }
700 
701     return JNI_TRUE;
702 }
703 
nativeDeferTransactionUntil(JNIEnv * env,jclass clazz,jlong nativeObject,jobject handleObject,jlong frameNumber)704 static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject,
705         jobject handleObject, jlong frameNumber) {
706     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
707     sp<IBinder> handle = ibinderForJavaObject(env, handleObject);
708 
709     ctrl->deferTransactionUntil(handle, frameNumber);
710 }
711 
nativeDeferTransactionUntilSurface(JNIEnv * env,jclass clazz,jlong nativeObject,jlong surfaceObject,jlong frameNumber)712 static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong nativeObject,
713         jlong surfaceObject, jlong frameNumber) {
714     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
715     sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject);
716 
717     ctrl->deferTransactionUntil(barrier, frameNumber);
718 }
719 
nativeReparentChildren(JNIEnv * env,jclass clazz,jlong nativeObject,jobject newParentObject)720 static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong nativeObject,
721         jobject newParentObject) {
722     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
723     sp<IBinder> handle = ibinderForJavaObject(env, newParentObject);
724 
725     ctrl->reparentChildren(handle);
726 }
727 
nativeSeverChildren(JNIEnv * env,jclass clazz,jlong nativeObject)728 static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong nativeObject) {
729     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
730     ctrl->detachChildren();
731 }
732 
nativeSetOverrideScalingMode(JNIEnv * env,jclass clazz,jlong nativeObject,jint scalingMode)733 static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong nativeObject,
734         jint scalingMode) {
735     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
736 
737     ctrl->setOverrideScalingMode(scalingMode);
738 }
739 
nativeGetHandle(JNIEnv * env,jclass clazz,jlong nativeObject)740 static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
741     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
742 
743     return javaObjectForIBinder(env, ctrl->getHandle());
744 }
745 
nativeGetHdrCapabilities(JNIEnv * env,jclass clazz,jobject tokenObject)746 static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject tokenObject) {
747     sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
748     if (token == NULL) return NULL;
749 
750     HdrCapabilities capabilities;
751     SurfaceComposerClient::getHdrCapabilities(token, &capabilities);
752 
753     const auto& types = capabilities.getSupportedHdrTypes();
754     auto typesArray = env->NewIntArray(types.size());
755     env->SetIntArrayRegion(typesArray, 0, types.size(), types.data());
756 
757     return env->NewObject(gHdrCapabilitiesClassInfo.clazz, gHdrCapabilitiesClassInfo.ctor,
758             typesArray, capabilities.getDesiredMaxLuminance(),
759             capabilities.getDesiredMaxAverageLuminance(), capabilities.getDesiredMinLuminance());
760 }
761 
762 // ----------------------------------------------------------------------------
763 
764 static const JNINativeMethod sSurfaceControlMethods[] = {
765     {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJII)J",
766             (void*)nativeCreate },
767     {"nativeRelease", "(J)V",
768             (void*)nativeRelease },
769     {"nativeDestroy", "(J)V",
770             (void*)nativeDestroy },
771     {"nativeDisconnect", "(J)V",
772             (void*)nativeDisconnect },
773     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
774             (void*)nativeScreenshotBitmap },
775     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
776             (void*)nativeScreenshot },
777     {"nativeOpenTransaction", "()V",
778             (void*)nativeOpenTransaction },
779     {"nativeCloseTransaction", "(Z)V",
780             (void*)nativeCloseTransaction },
781     {"nativeSetAnimationTransaction", "()V",
782             (void*)nativeSetAnimationTransaction },
783     {"nativeSetLayer", "(JI)V",
784             (void*)nativeSetLayer },
785     {"nativeSetRelativeLayer", "(JLandroid/os/IBinder;I)V",
786             (void*)nativeSetRelativeLayer },
787     {"nativeSetPosition", "(JFF)V",
788             (void*)nativeSetPosition },
789     {"nativeSetGeometryAppliesWithResize", "(J)V",
790             (void*)nativeSetGeometryAppliesWithResize },
791     {"nativeSetSize", "(JII)V",
792             (void*)nativeSetSize },
793     {"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",
794             (void*)nativeSetTransparentRegionHint },
795     {"nativeSetAlpha", "(JF)V",
796             (void*)nativeSetAlpha },
797     {"nativeSetMatrix", "(JFFFF)V",
798             (void*)nativeSetMatrix },
799     {"nativeSetFlags", "(JII)V",
800             (void*)nativeSetFlags },
801     {"nativeSetWindowCrop", "(JIIII)V",
802             (void*)nativeSetWindowCrop },
803     {"nativeSetFinalCrop", "(JIIII)V",
804             (void*)nativeSetFinalCrop },
805     {"nativeSetLayerStack", "(JI)V",
806             (void*)nativeSetLayerStack },
807     {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
808             (void*)nativeGetBuiltInDisplay },
809     {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
810             (void*)nativeCreateDisplay },
811     {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
812             (void*)nativeDestroyDisplay },
813     {"nativeSetDisplaySurface", "(Landroid/os/IBinder;J)V",
814             (void*)nativeSetDisplaySurface },
815     {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
816             (void*)nativeSetDisplayLayerStack },
817     {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
818             (void*)nativeSetDisplayProjection },
819     {"nativeSetDisplaySize", "(Landroid/os/IBinder;II)V",
820             (void*)nativeSetDisplaySize },
821     {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
822             (void*)nativeGetDisplayConfigs },
823     {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
824             (void*)nativeGetActiveConfig },
825     {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
826             (void*)nativeSetActiveConfig },
827     {"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
828             (void*)nativeGetDisplayColorModes},
829     {"nativeGetActiveColorMode", "(Landroid/os/IBinder;)I",
830             (void*)nativeGetActiveColorMode},
831     {"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z",
832             (void*)nativeSetActiveColorMode},
833     {"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;",
834             (void*)nativeGetHdrCapabilities },
835     {"nativeClearContentFrameStats", "(J)Z",
836             (void*)nativeClearContentFrameStats },
837     {"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
838             (void*)nativeGetContentFrameStats },
839     {"nativeClearAnimationFrameStats", "()Z",
840             (void*)nativeClearAnimationFrameStats },
841     {"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
842             (void*)nativeGetAnimationFrameStats },
843     {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
844             (void*)nativeSetDisplayPowerMode },
845     {"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V",
846             (void*)nativeDeferTransactionUntil },
847     {"nativeDeferTransactionUntilSurface", "(JJJ)V",
848             (void*)nativeDeferTransactionUntilSurface },
849     {"nativeReparentChildren", "(JLandroid/os/IBinder;)V",
850             (void*)nativeReparentChildren } ,
851     {"nativeSeverChildren", "(J)V",
852             (void*)nativeSeverChildren } ,
853     {"nativeSetOverrideScalingMode", "(JI)V",
854             (void*)nativeSetOverrideScalingMode },
855     {"nativeGetHandle", "(J)Landroid/os/IBinder;",
856             (void*)nativeGetHandle },
857     {"nativeScreenshotToBuffer",
858      "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/GraphicBuffer;",
859      (void*)nativeScreenshotToBuffer },
860 };
861 
register_android_view_SurfaceControl(JNIEnv * env)862 int register_android_view_SurfaceControl(JNIEnv* env)
863 {
864     int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl",
865             sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
866 
867     jclass clazz = FindClassOrDie(env, "android/view/SurfaceControl$PhysicalDisplayInfo");
868     gPhysicalDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
869     gPhysicalDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env,
870             gPhysicalDisplayInfoClassInfo.clazz, "<init>", "()V");
871     gPhysicalDisplayInfoClassInfo.width =       GetFieldIDOrDie(env, clazz, "width", "I");
872     gPhysicalDisplayInfoClassInfo.height =      GetFieldIDOrDie(env, clazz, "height", "I");
873     gPhysicalDisplayInfoClassInfo.refreshRate = GetFieldIDOrDie(env, clazz, "refreshRate", "F");
874     gPhysicalDisplayInfoClassInfo.density =     GetFieldIDOrDie(env, clazz, "density", "F");
875     gPhysicalDisplayInfoClassInfo.xDpi =        GetFieldIDOrDie(env, clazz, "xDpi", "F");
876     gPhysicalDisplayInfoClassInfo.yDpi =        GetFieldIDOrDie(env, clazz, "yDpi", "F");
877     gPhysicalDisplayInfoClassInfo.secure =      GetFieldIDOrDie(env, clazz, "secure", "Z");
878     gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = GetFieldIDOrDie(env,
879             clazz, "appVsyncOffsetNanos", "J");
880     gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env,
881             clazz, "presentationDeadlineNanos", "J");
882 
883     jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
884     gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
885     gRectClassInfo.left =   GetFieldIDOrDie(env, rectClazz, "left", "I");
886     gRectClassInfo.right =  GetFieldIDOrDie(env, rectClazz, "right", "I");
887     gRectClassInfo.top =    GetFieldIDOrDie(env, rectClazz, "top", "I");
888 
889     jclass frameStatsClazz = FindClassOrDie(env, "android/view/FrameStats");
890     jfieldID undefined_time_nano_field = GetStaticFieldIDOrDie(env,
891             frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
892     nsecs_t undefined_time_nano = env->GetStaticLongField(frameStatsClazz, undefined_time_nano_field);
893 
894     jclass contFrameStatsClazz = FindClassOrDie(env, "android/view/WindowContentFrameStats");
895     gWindowContentFrameStatsClassInfo.init = GetMethodIDOrDie(env,
896             contFrameStatsClazz, "init", "(J[J[J[J)V");
897     gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
898 
899     jclass animFrameStatsClazz = FindClassOrDie(env, "android/view/WindowAnimationFrameStats");
900     gWindowAnimationFrameStatsClassInfo.init =  GetMethodIDOrDie(env,
901             animFrameStatsClazz, "init", "(J[J)V");
902     gWindowAnimationFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
903 
904     jclass hdrCapabilitiesClazz = FindClassOrDie(env, "android/view/Display$HdrCapabilities");
905     gHdrCapabilitiesClassInfo.clazz = MakeGlobalRefOrDie(env, hdrCapabilitiesClazz);
906     gHdrCapabilitiesClassInfo.ctor = GetMethodIDOrDie(env, hdrCapabilitiesClazz, "<init>",
907             "([IFFF)V");
908 
909     jclass graphicsBufferClazz = FindClassOrDie(env, "android/graphics/GraphicBuffer");
910     gGraphicBufferClassInfo.clazz = MakeGlobalRefOrDie(env, graphicsBufferClazz);
911     gGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env, graphicsBufferClazz,
912             "createFromExisting", "(IIIIJ)Landroid/graphics/GraphicBuffer;");
913 
914     return err;
915 }
916 
917 };
918