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